@vaadin/avatar-group 23.3.0-alpha2 → 24.0.0-alpha1
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 +10 -10
- package/src/vaadin-avatar-group-overlay.js +4 -4
- package/src/vaadin-avatar-group.d.ts +5 -3
- package/src/vaadin-avatar-group.js +224 -84
- package/theme/lumo/vaadin-avatar-group-styles.js +3 -14
- package/theme/lumo/vaadin-avatar-group.js +1 -1
- package/theme/material/vaadin-avatar-group-styles.js +3 -14
- package/theme/material/vaadin-avatar-group.js +1 -1
- package/web-types.json +3 -3
- package/web-types.lit.json +3 -3
- package/src/vaadin-avatar-group-list-box.js +0 -20
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vaadin/avatar-group",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "24.0.0-alpha1",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -37,14 +37,14 @@
|
|
|
37
37
|
],
|
|
38
38
|
"dependencies": {
|
|
39
39
|
"@polymer/polymer": "^3.0.0",
|
|
40
|
-
"@vaadin/avatar": "
|
|
41
|
-
"@vaadin/component-base": "
|
|
42
|
-
"@vaadin/item": "
|
|
43
|
-
"@vaadin/list-box": "
|
|
44
|
-
"@vaadin/
|
|
45
|
-
"@vaadin/vaadin-
|
|
46
|
-
"@vaadin/vaadin-
|
|
47
|
-
"@vaadin/vaadin-themable-mixin": "
|
|
40
|
+
"@vaadin/avatar": "24.0.0-alpha1",
|
|
41
|
+
"@vaadin/component-base": "24.0.0-alpha1",
|
|
42
|
+
"@vaadin/item": "24.0.0-alpha1",
|
|
43
|
+
"@vaadin/list-box": "24.0.0-alpha1",
|
|
44
|
+
"@vaadin/overlay": "24.0.0-alpha1",
|
|
45
|
+
"@vaadin/vaadin-lumo-styles": "24.0.0-alpha1",
|
|
46
|
+
"@vaadin/vaadin-material-styles": "24.0.0-alpha1",
|
|
47
|
+
"@vaadin/vaadin-themable-mixin": "24.0.0-alpha1"
|
|
48
48
|
},
|
|
49
49
|
"devDependencies": {
|
|
50
50
|
"@esm-bundle/chai": "^4.3.4",
|
|
@@ -55,5 +55,5 @@
|
|
|
55
55
|
"web-types.json",
|
|
56
56
|
"web-types.lit.json"
|
|
57
57
|
],
|
|
58
|
-
"gitHead": "
|
|
58
|
+
"gitHead": "427527c27c4b27822d61fd41d38d7b170134770b"
|
|
59
59
|
}
|
|
@@ -3,16 +3,16 @@
|
|
|
3
3
|
* Copyright (c) 2020 - 2022 Vaadin Ltd.
|
|
4
4
|
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
5
5
|
*/
|
|
6
|
-
import {
|
|
7
|
-
import { PositionMixin } from '@vaadin/
|
|
6
|
+
import { Overlay } from '@vaadin/overlay/src/vaadin-overlay.js';
|
|
7
|
+
import { PositionMixin } from '@vaadin/overlay/src/vaadin-overlay-position-mixin.js';
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* An element used internally by `<vaadin-avatar-group>`. Not intended to be used separately.
|
|
11
11
|
*
|
|
12
|
-
* @extends
|
|
12
|
+
* @extends Overlay
|
|
13
13
|
* @private
|
|
14
14
|
*/
|
|
15
|
-
class AvatarGroupOverlay extends PositionMixin(
|
|
15
|
+
class AvatarGroupOverlay extends PositionMixin(Overlay) {
|
|
16
16
|
static get is() {
|
|
17
17
|
return 'vaadin-avatar-group-overlay';
|
|
18
18
|
}
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
5
5
|
*/
|
|
6
6
|
import { AvatarI18n } from '@vaadin/avatar/src/vaadin-avatar.js';
|
|
7
|
+
import { ControllerMixin } from '@vaadin/component-base/src/controller-mixin.js';
|
|
7
8
|
import { ElementMixin } from '@vaadin/component-base/src/element-mixin.js';
|
|
8
9
|
import { ResizeMixin } from '@vaadin/component-base/src/resize-mixin.js';
|
|
9
10
|
import { ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
|
|
@@ -51,7 +52,9 @@ export interface AvatarGroupItem {
|
|
|
51
52
|
* Part name | Description
|
|
52
53
|
* ----------- | ---------------
|
|
53
54
|
* `container` | The container element
|
|
54
|
-
*
|
|
55
|
+
*
|
|
56
|
+
* See the [`<vaadin-avatar>`](#/elements/vaadin-avatar) documentation for the available
|
|
57
|
+
* state attributes and stylable shadow parts of avatar elements.
|
|
55
58
|
*
|
|
56
59
|
* See [Styling Components](https://vaadin.com/docs/latest/styling/custom-theme/styling-components) documentation.
|
|
57
60
|
*
|
|
@@ -60,10 +63,9 @@ export interface AvatarGroupItem {
|
|
|
60
63
|
* In addition to `<vaadin-avatar-group>` itself, the following internal
|
|
61
64
|
* components are themable:
|
|
62
65
|
*
|
|
63
|
-
* - `<vaadin-avatar-group-list-box>` - has the same API as [`<vaadin-list-box>`](#/elements/vaadin-list-box).
|
|
64
66
|
* - `<vaadin-avatar-group-overlay>` - has the same API as [`<vaadin-overlay>`](#/elements/vaadin-overlay).
|
|
65
67
|
*/
|
|
66
|
-
declare class AvatarGroup extends ResizeMixin(ElementMixin(ThemableMixin(HTMLElement))) {
|
|
68
|
+
declare class AvatarGroup extends ResizeMixin(ElementMixin(ThemableMixin(ControllerMixin(HTMLElement)))) {
|
|
67
69
|
readonly _avatars: HTMLElement[];
|
|
68
70
|
|
|
69
71
|
/**
|
|
@@ -3,17 +3,18 @@
|
|
|
3
3
|
* Copyright (c) 2020 - 2022 Vaadin Ltd.
|
|
4
4
|
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
5
5
|
*/
|
|
6
|
-
import '@polymer/polymer/lib/elements/dom-repeat.js';
|
|
7
6
|
import '@vaadin/avatar/src/vaadin-avatar.js';
|
|
8
7
|
import '@vaadin/item/src/vaadin-item.js';
|
|
9
|
-
import '
|
|
8
|
+
import '@vaadin/list-box/src/vaadin-list-box.js';
|
|
10
9
|
import './vaadin-avatar-group-overlay.js';
|
|
11
10
|
import { calculateSplices } from '@polymer/polymer/lib/utils/array-splice.js';
|
|
12
11
|
import { afterNextRender } from '@polymer/polymer/lib/utils/render-status.js';
|
|
13
12
|
import { html, PolymerElement } from '@polymer/polymer/polymer-element.js';
|
|
14
13
|
import { announce } from '@vaadin/component-base/src/a11y-announcer.js';
|
|
14
|
+
import { ControllerMixin } from '@vaadin/component-base/src/controller-mixin.js';
|
|
15
15
|
import { ElementMixin } from '@vaadin/component-base/src/element-mixin.js';
|
|
16
16
|
import { ResizeMixin } from '@vaadin/component-base/src/resize-mixin.js';
|
|
17
|
+
import { SlotController } from '@vaadin/component-base/src/slot-controller.js';
|
|
17
18
|
import { ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
|
|
18
19
|
|
|
19
20
|
const MINIMUM_DISPLAYED_AVATARS = 2;
|
|
@@ -43,7 +44,9 @@ const MINIMUM_DISPLAYED_AVATARS = 2;
|
|
|
43
44
|
* Part name | Description
|
|
44
45
|
* ----------- | ---------------
|
|
45
46
|
* `container` | The container element
|
|
46
|
-
*
|
|
47
|
+
*
|
|
48
|
+
* See the [`<vaadin-avatar>`](#/elements/vaadin-avatar) documentation for the available
|
|
49
|
+
* state attributes and stylable shadow parts of avatar elements.
|
|
47
50
|
*
|
|
48
51
|
* See [Styling Components](https://vaadin.com/docs/latest/styling/custom-theme/styling-components) documentation.
|
|
49
52
|
*
|
|
@@ -52,15 +55,15 @@ const MINIMUM_DISPLAYED_AVATARS = 2;
|
|
|
52
55
|
* In addition to `<vaadin-avatar-group>` itself, the following internal
|
|
53
56
|
* components are themable:
|
|
54
57
|
*
|
|
55
|
-
* - `<vaadin-avatar-group-list-box>` - has the same API as [`<vaadin-list-box>`](#/elements/vaadin-list-box).
|
|
56
58
|
* - `<vaadin-avatar-group-overlay>` - has the same API as [`<vaadin-overlay>`](#/elements/vaadin-overlay).
|
|
57
59
|
*
|
|
58
60
|
* @extends HTMLElement
|
|
61
|
+
* @mixes ControllerMixin
|
|
59
62
|
* @mixes ElementMixin
|
|
60
63
|
* @mixes ThemableMixin
|
|
61
64
|
* @mixes ResizeMixin
|
|
62
65
|
*/
|
|
63
|
-
class AvatarGroup extends ResizeMixin(ElementMixin(ThemableMixin(PolymerElement))) {
|
|
66
|
+
class AvatarGroup extends ResizeMixin(ElementMixin(ThemableMixin(ControllerMixin(PolymerElement)))) {
|
|
64
67
|
static get template() {
|
|
65
68
|
return html`
|
|
66
69
|
<style>
|
|
@@ -82,7 +85,7 @@ class AvatarGroup extends ResizeMixin(ElementMixin(ThemableMixin(PolymerElement)
|
|
|
82
85
|
flex-wrap: nowrap;
|
|
83
86
|
}
|
|
84
87
|
|
|
85
|
-
|
|
88
|
+
::slotted(vaadin-avatar:not(:first-child)) {
|
|
86
89
|
-webkit-mask-image: url('data:image/svg+xml;utf8,<svg viewBox=%220 0 300 300%22 fill=%22none%22 xmlns=%22http://www.w3.org/2000/svg%22><path fill-rule=%22evenodd%22 clip-rule=%22evenodd%22 d=%22M300 0H0V300H300V0ZM150 200C177.614 200 200 177.614 200 150C200 122.386 177.614 100 150 100C122.386 100 100 122.386 100 150C100 177.614 122.386 200 150 200Z%22 fill=%22black%22/></svg>');
|
|
87
90
|
mask-image: url('data:image/svg+xml;utf8,<svg viewBox=%220 0 300 300%22 fill=%22none%22 xmlns=%22http://www.w3.org/2000/svg%22><path fill-rule=%22evenodd%22 clip-rule=%22evenodd%22 d=%22M300 0H0V300H300V0ZM150 200C177.614 200 200 177.614 200 150C200 122.386 177.614 100 150 100C122.386 100 100 122.386 100 150C100 177.614 122.386 200 150 200Z%22 fill=%22black%22/></svg>');
|
|
88
91
|
-webkit-mask-size: calc(
|
|
@@ -93,13 +96,13 @@ class AvatarGroup extends ResizeMixin(ElementMixin(ThemableMixin(PolymerElement)
|
|
|
93
96
|
);
|
|
94
97
|
}
|
|
95
98
|
|
|
96
|
-
|
|
99
|
+
::slotted(vaadin-avatar:not([dir='rtl']):not(:first-child)) {
|
|
97
100
|
margin-left: calc(var(--vaadin-avatar-group-overlap) * -1 - var(--vaadin-avatar-outline-width));
|
|
98
101
|
-webkit-mask-position: calc(50% - var(--vaadin-avatar-size) + var(--vaadin-avatar-group-overlap));
|
|
99
102
|
mask-position: calc(50% - var(--vaadin-avatar-size) + var(--vaadin-avatar-group-overlap));
|
|
100
103
|
}
|
|
101
104
|
|
|
102
|
-
|
|
105
|
+
::slotted(vaadin-avatar[dir='rtl']:not(:first-child)) {
|
|
103
106
|
margin-right: calc(var(--vaadin-avatar-group-overlap) * -1);
|
|
104
107
|
-webkit-mask-position: calc(
|
|
105
108
|
50% + var(--vaadin-avatar-size) - var(--vaadin-avatar-group-overlap) + var(--vaadin-avatar-outline-width)
|
|
@@ -110,58 +113,16 @@ class AvatarGroup extends ResizeMixin(ElementMixin(ThemableMixin(PolymerElement)
|
|
|
110
113
|
}
|
|
111
114
|
</style>
|
|
112
115
|
<div id="container" part="container">
|
|
113
|
-
<
|
|
114
|
-
|
|
115
|
-
name="[[item.name]]"
|
|
116
|
-
abbr="[[item.abbr]]"
|
|
117
|
-
img="[[item.img]]"
|
|
118
|
-
part="avatar"
|
|
119
|
-
theme$="[[_theme]]"
|
|
120
|
-
i18n="[[i18n]]"
|
|
121
|
-
color-index="[[item.colorIndex]]"
|
|
122
|
-
with-tooltip
|
|
123
|
-
></vaadin-avatar>
|
|
124
|
-
</template>
|
|
125
|
-
<vaadin-avatar
|
|
126
|
-
id="overflow"
|
|
127
|
-
part="avatar"
|
|
128
|
-
hidden$="[[__computeMoreHidden(items.length, __itemsInView, __maxReached)]]"
|
|
129
|
-
abbr="[[__computeMore(items.length, __itemsInView, maxItemsVisible)]]"
|
|
130
|
-
theme$="[[_theme]]"
|
|
131
|
-
on-click="_onOverflowClick"
|
|
132
|
-
on-keydown="_onOverflowKeyDown"
|
|
133
|
-
aria-haspopup="listbox"
|
|
134
|
-
>
|
|
135
|
-
<vaadin-tooltip slot="tooltip" generator="[[__overflowTextGenerator]]"></vaadin-tooltip>
|
|
136
|
-
</vaadin-avatar>
|
|
116
|
+
<slot></slot>
|
|
117
|
+
<slot name="overflow"></slot>
|
|
137
118
|
</div>
|
|
138
119
|
<vaadin-avatar-group-overlay
|
|
139
120
|
id="overlay"
|
|
140
121
|
opened="{{_opened}}"
|
|
122
|
+
position-target="[[_overflow]]"
|
|
141
123
|
no-vertical-overlap
|
|
142
124
|
on-vaadin-overlay-close="_onVaadinOverlayClose"
|
|
143
|
-
>
|
|
144
|
-
<template>
|
|
145
|
-
<vaadin-avatar-group-list-box on-keydown="_onListKeyDown">
|
|
146
|
-
<template is="dom-repeat" items="[[__computeExtraItems(items.*, __itemsInView, maxItemsVisible)]]">
|
|
147
|
-
<vaadin-item theme="avatar-group-item" role="option">
|
|
148
|
-
<vaadin-avatar
|
|
149
|
-
name="[[item.name]]"
|
|
150
|
-
abbr="[[item.abbr]]"
|
|
151
|
-
img="[[item.img]]"
|
|
152
|
-
i18n="[[i18n]]"
|
|
153
|
-
part="avatar"
|
|
154
|
-
theme$="[[_theme]]"
|
|
155
|
-
color-index="[[item.colorIndex]]"
|
|
156
|
-
tabindex="-1"
|
|
157
|
-
aria-hidden="true"
|
|
158
|
-
></vaadin-avatar>
|
|
159
|
-
[[item.name]]
|
|
160
|
-
</vaadin-item>
|
|
161
|
-
</template>
|
|
162
|
-
</vaadin-avatar-group-list-box>
|
|
163
|
-
</template>
|
|
164
|
-
</vaadin-avatar-group-overlay>
|
|
125
|
+
></vaadin-avatar-group-overlay>
|
|
165
126
|
`;
|
|
166
127
|
}
|
|
167
128
|
|
|
@@ -254,35 +215,63 @@ class AvatarGroup extends ResizeMixin(ElementMixin(ThemableMixin(PolymerElement)
|
|
|
254
215
|
},
|
|
255
216
|
},
|
|
256
217
|
|
|
218
|
+
/** @private */
|
|
219
|
+
_avatars: {
|
|
220
|
+
type: Array,
|
|
221
|
+
value: () => [],
|
|
222
|
+
},
|
|
223
|
+
|
|
257
224
|
/** @private */
|
|
258
225
|
__maxReached: {
|
|
259
226
|
type: Boolean,
|
|
260
227
|
computed: '__computeMaxReached(items.length, maxItemsVisible)',
|
|
261
228
|
},
|
|
262
229
|
|
|
230
|
+
/** @private */
|
|
231
|
+
__items: {
|
|
232
|
+
type: Array,
|
|
233
|
+
},
|
|
234
|
+
|
|
263
235
|
/** @private */
|
|
264
236
|
__itemsInView: {
|
|
265
237
|
type: Number,
|
|
266
238
|
value: null,
|
|
267
239
|
},
|
|
268
240
|
|
|
241
|
+
/** @private */
|
|
242
|
+
_overflow: {
|
|
243
|
+
type: Object,
|
|
244
|
+
},
|
|
245
|
+
|
|
246
|
+
/** @private */
|
|
247
|
+
_overflowItems: {
|
|
248
|
+
type: Array,
|
|
249
|
+
observer: '__overflowItemsChanged',
|
|
250
|
+
computed: '__computeOverflowItems(items.*, __itemsInView, maxItemsVisible)',
|
|
251
|
+
},
|
|
252
|
+
|
|
253
|
+
/** @private */
|
|
254
|
+
_overflowTooltip: {
|
|
255
|
+
type: Object,
|
|
256
|
+
},
|
|
257
|
+
|
|
269
258
|
/** @private */
|
|
270
259
|
_opened: {
|
|
271
260
|
type: Boolean,
|
|
272
261
|
observer: '__openedChanged',
|
|
273
|
-
value: false,
|
|
274
262
|
},
|
|
275
|
-
|
|
276
|
-
/** @private */
|
|
277
|
-
__overflowTextGenerator: Object,
|
|
278
263
|
};
|
|
279
264
|
}
|
|
280
265
|
|
|
281
266
|
static get observers() {
|
|
282
267
|
return [
|
|
283
|
-
'__computeMoreTooltip(items.length, __itemsInView, maxItemsVisible)',
|
|
284
268
|
'__itemsChanged(items.splices, items.*)',
|
|
285
269
|
'__i18nItemsChanged(i18n.*, items.length)',
|
|
270
|
+
'__updateAvatarsTheme(_overflow, _avatars, _theme)',
|
|
271
|
+
'__updateAvatars(items.*, __itemsInView, maxItemsVisible)',
|
|
272
|
+
'__updateOverflowAbbr(_overflow, items.length, __itemsInView, maxItemsVisible)',
|
|
273
|
+
'__updateOverflowHidden(_overflow, items.length, __itemsInView, __maxReached)',
|
|
274
|
+
'__updateOverflowTooltip(_overflowTooltip, items.length, __itemsInView, maxItemsVisible)',
|
|
286
275
|
];
|
|
287
276
|
}
|
|
288
277
|
|
|
@@ -290,20 +279,38 @@ class AvatarGroup extends ResizeMixin(ElementMixin(ThemableMixin(PolymerElement)
|
|
|
290
279
|
ready() {
|
|
291
280
|
super.ready();
|
|
292
281
|
|
|
293
|
-
this.
|
|
294
|
-
|
|
282
|
+
this._overflowController = new SlotController(
|
|
283
|
+
this,
|
|
284
|
+
'overflow',
|
|
285
|
+
() => document.createElement('vaadin-avatar'),
|
|
286
|
+
(_, overflow) => {
|
|
287
|
+
overflow.setAttribute('aria-haspopup', 'listbox');
|
|
288
|
+
overflow.setAttribute('aria-expanded', 'false');
|
|
289
|
+
overflow.addEventListener('click', (e) => this._onOverflowClick(e));
|
|
290
|
+
overflow.addEventListener('keydown', (e) => this._onOverflowKeyDown(e));
|
|
291
|
+
|
|
292
|
+
const tooltip = document.createElement('vaadin-tooltip');
|
|
293
|
+
tooltip.setAttribute('slot', 'tooltip');
|
|
294
|
+
overflow.appendChild(tooltip);
|
|
295
|
+
|
|
296
|
+
this._overflow = overflow;
|
|
297
|
+
this._overflowTooltip = tooltip;
|
|
298
|
+
},
|
|
299
|
+
);
|
|
300
|
+
this.addController(this._overflowController);
|
|
301
|
+
|
|
302
|
+
this.$.overlay.renderer = this.__overlayRenderer.bind(this);
|
|
295
303
|
|
|
296
304
|
afterNextRender(this, () => {
|
|
297
305
|
this.__setItemsInView();
|
|
298
306
|
});
|
|
299
307
|
}
|
|
300
308
|
|
|
301
|
-
/**
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
return this.shadowRoot.querySelectorAll('vaadin-avatar');
|
|
309
|
+
/** @protected */
|
|
310
|
+
disconnectedCallback() {
|
|
311
|
+
super.disconnectedCallback();
|
|
312
|
+
|
|
313
|
+
this._opened = false;
|
|
307
314
|
}
|
|
308
315
|
|
|
309
316
|
/** @private */
|
|
@@ -311,6 +318,76 @@ class AvatarGroup extends ResizeMixin(ElementMixin(ThemableMixin(PolymerElement)
|
|
|
311
318
|
return action.replace('{user}', user.name || user.abbr || this.i18n.anonymous);
|
|
312
319
|
}
|
|
313
320
|
|
|
321
|
+
/**
|
|
322
|
+
* Renders items when they are provided by the `items` property and clears the content otherwise.
|
|
323
|
+
* @param {!HTMLElement} root
|
|
324
|
+
* @param {!Select} _select
|
|
325
|
+
* @private
|
|
326
|
+
*/
|
|
327
|
+
__overlayRenderer(root) {
|
|
328
|
+
let listBox = root.firstElementChild;
|
|
329
|
+
if (!listBox) {
|
|
330
|
+
listBox = document.createElement('vaadin-list-box');
|
|
331
|
+
listBox.addEventListener('keydown', (event) => this._onListKeyDown(event));
|
|
332
|
+
root.appendChild(listBox);
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
listBox.textContent = '';
|
|
336
|
+
|
|
337
|
+
if (!this._overflowItems) {
|
|
338
|
+
return;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
this._overflowItems.forEach((item) => {
|
|
342
|
+
listBox.appendChild(this.__createItemElement(item));
|
|
343
|
+
});
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
/** @private */
|
|
347
|
+
__createAvatar(item) {
|
|
348
|
+
const avatar = document.createElement('vaadin-avatar');
|
|
349
|
+
avatar.name = item.name;
|
|
350
|
+
avatar.abbr = item.abbr;
|
|
351
|
+
avatar.img = item.img;
|
|
352
|
+
avatar.colorIndex = item.colorIndex;
|
|
353
|
+
|
|
354
|
+
avatar.withTooltip = true;
|
|
355
|
+
avatar.i18n = this.i18n;
|
|
356
|
+
avatar._item = item;
|
|
357
|
+
|
|
358
|
+
return avatar;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
/** @private */
|
|
362
|
+
__createItemElement(item) {
|
|
363
|
+
const itemElement = document.createElement('vaadin-item');
|
|
364
|
+
itemElement.setAttribute('theme', 'avatar-group-item');
|
|
365
|
+
itemElement.setAttribute('role', 'option');
|
|
366
|
+
|
|
367
|
+
const avatar = document.createElement('vaadin-avatar');
|
|
368
|
+
itemElement.appendChild(avatar);
|
|
369
|
+
|
|
370
|
+
avatar.setAttribute('aria-hidden', 'true');
|
|
371
|
+
avatar.setAttribute('tabindex', '-1');
|
|
372
|
+
avatar.i18n = this.i18n;
|
|
373
|
+
|
|
374
|
+
if (this._theme) {
|
|
375
|
+
avatar.setAttribute('theme', this._theme);
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
avatar.name = item.name;
|
|
379
|
+
avatar.abbr = item.abbr;
|
|
380
|
+
avatar.img = item.img;
|
|
381
|
+
avatar.colorIndex = item.colorIndex;
|
|
382
|
+
|
|
383
|
+
if (item.name) {
|
|
384
|
+
const text = document.createTextNode(item.name);
|
|
385
|
+
itemElement.appendChild(text);
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
return itemElement;
|
|
389
|
+
}
|
|
390
|
+
|
|
314
391
|
/** @private */
|
|
315
392
|
_onOverflowClick(e) {
|
|
316
393
|
e.stopPropagation();
|
|
@@ -354,17 +431,48 @@ class AvatarGroup extends ResizeMixin(ElementMixin(ThemableMixin(PolymerElement)
|
|
|
354
431
|
}
|
|
355
432
|
|
|
356
433
|
/** @private */
|
|
357
|
-
|
|
434
|
+
__updateAvatars(arr, itemsInView, maxItemsVisible) {
|
|
358
435
|
const items = arr.base || [];
|
|
359
436
|
const limit = this.__getLimit(items.length, itemsInView, maxItemsVisible);
|
|
360
|
-
|
|
437
|
+
|
|
438
|
+
const newItems = limit ? items.slice(0, limit) : items;
|
|
439
|
+
const oldItems = this.__oldAvatarItems || [];
|
|
440
|
+
|
|
441
|
+
if (newItems.length || oldItems.length) {
|
|
442
|
+
const removed = oldItems.filter((item) => !newItems.includes(item));
|
|
443
|
+
const added = [...newItems];
|
|
444
|
+
|
|
445
|
+
this._avatars.forEach((avatar) => {
|
|
446
|
+
const item = avatar._item;
|
|
447
|
+
if (removed.includes(item)) {
|
|
448
|
+
avatar.remove();
|
|
449
|
+
} else if (added.includes(item)) {
|
|
450
|
+
added.splice(added.indexOf(item), 1);
|
|
451
|
+
}
|
|
452
|
+
});
|
|
453
|
+
|
|
454
|
+
this.__addAvatars(added, newItems);
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
this._avatars = [...this.querySelectorAll('vaadin-avatar')];
|
|
458
|
+
this.__oldAvatarItems = newItems;
|
|
361
459
|
}
|
|
362
460
|
|
|
363
461
|
/** @private */
|
|
364
|
-
|
|
462
|
+
__addAvatars(itemsToAdd, allItems) {
|
|
463
|
+
itemsToAdd.forEach((item) => {
|
|
464
|
+
const avatar = this.__createAvatar(item);
|
|
465
|
+
const nextItem = allItems[allItems.indexOf(item) + 1];
|
|
466
|
+
const nextAvatar = this._avatars.find((el) => el._item === nextItem);
|
|
467
|
+
this.insertBefore(avatar, nextAvatar || this._overflow);
|
|
468
|
+
});
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
/** @private */
|
|
472
|
+
__computeOverflowItems(arr, itemsInView, maxItemsVisible) {
|
|
365
473
|
const items = arr.base || [];
|
|
366
474
|
const limit = this.__getLimit(items.length, itemsInView, maxItemsVisible);
|
|
367
|
-
return limit ? items.slice(limit) :
|
|
475
|
+
return limit ? items.slice(limit) : [];
|
|
368
476
|
}
|
|
369
477
|
|
|
370
478
|
/** @private */
|
|
@@ -373,21 +481,43 @@ class AvatarGroup extends ResizeMixin(ElementMixin(ThemableMixin(PolymerElement)
|
|
|
373
481
|
}
|
|
374
482
|
|
|
375
483
|
/** @private */
|
|
376
|
-
|
|
377
|
-
|
|
484
|
+
__updateOverflowAbbr(overflow, items, itemsInView, maxItemsVisible) {
|
|
485
|
+
if (overflow) {
|
|
486
|
+
overflow.abbr = `+${items - this.__getLimit(items, itemsInView, maxItemsVisible)}`;
|
|
487
|
+
}
|
|
378
488
|
}
|
|
379
489
|
|
|
380
490
|
/** @private */
|
|
381
|
-
|
|
382
|
-
|
|
491
|
+
__updateOverflowHidden(overflow, items, itemsInView, maxReached) {
|
|
492
|
+
if (overflow) {
|
|
493
|
+
overflow.toggleAttribute('hidden', !maxReached && !(itemsInView && itemsInView < items));
|
|
494
|
+
}
|
|
383
495
|
}
|
|
384
496
|
|
|
385
497
|
/** @private */
|
|
386
|
-
|
|
498
|
+
__updateAvatarsTheme(overflow, avatars, theme) {
|
|
499
|
+
if (overflow) {
|
|
500
|
+
[overflow, ...avatars].forEach((avatar) => {
|
|
501
|
+
if (theme) {
|
|
502
|
+
avatar.setAttribute('theme', theme);
|
|
503
|
+
} else {
|
|
504
|
+
avatar.removeAttribute('theme');
|
|
505
|
+
}
|
|
506
|
+
});
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
/** @private */
|
|
511
|
+
__updateOverflowTooltip(tooltip, items, itemsInView, maxItemsVisible) {
|
|
512
|
+
if (!tooltip) {
|
|
513
|
+
return;
|
|
514
|
+
}
|
|
515
|
+
|
|
387
516
|
const limit = this.__getLimit(items, itemsInView, maxItemsVisible);
|
|
388
517
|
if (limit == null) {
|
|
389
518
|
return;
|
|
390
519
|
}
|
|
520
|
+
|
|
391
521
|
const result = [];
|
|
392
522
|
for (let i = limit; i < items; i++) {
|
|
393
523
|
const item = this.items[i];
|
|
@@ -395,8 +525,8 @@ class AvatarGroup extends ResizeMixin(ElementMixin(ThemableMixin(PolymerElement)
|
|
|
395
525
|
result.push(item.name || item.abbr || 'anonymous');
|
|
396
526
|
}
|
|
397
527
|
}
|
|
398
|
-
|
|
399
|
-
|
|
528
|
+
|
|
529
|
+
tooltip.text = result.join('\n');
|
|
400
530
|
}
|
|
401
531
|
|
|
402
532
|
/** @private */
|
|
@@ -421,7 +551,6 @@ class AvatarGroup extends ResizeMixin(ElementMixin(ThemableMixin(PolymerElement)
|
|
|
421
551
|
/** @private */
|
|
422
552
|
__itemsChanged(splices, itemsChange) {
|
|
423
553
|
const items = itemsChange.base;
|
|
424
|
-
this.$.items.render();
|
|
425
554
|
this.__setItemsInView();
|
|
426
555
|
|
|
427
556
|
// Mutation using group.splice('items')
|
|
@@ -469,6 +598,10 @@ class AvatarGroup extends ResizeMixin(ElementMixin(ThemableMixin(PolymerElement)
|
|
|
469
598
|
if (base.activeUsers[field]) {
|
|
470
599
|
this.setAttribute('aria-label', base.activeUsers[field].replace('{count}', items || 0));
|
|
471
600
|
}
|
|
601
|
+
|
|
602
|
+
this._avatars.forEach((avatar) => {
|
|
603
|
+
avatar.i18n = base;
|
|
604
|
+
});
|
|
472
605
|
}
|
|
473
606
|
}
|
|
474
607
|
|
|
@@ -476,20 +609,27 @@ class AvatarGroup extends ResizeMixin(ElementMixin(ThemableMixin(PolymerElement)
|
|
|
476
609
|
__openedChanged(opened, wasOpened) {
|
|
477
610
|
if (opened) {
|
|
478
611
|
if (!this._menuElement) {
|
|
479
|
-
this._menuElement = this.
|
|
612
|
+
this._menuElement = this.$.overlay.querySelector('vaadin-list-box');
|
|
480
613
|
this._menuElement.setAttribute('role', 'listbox');
|
|
481
614
|
}
|
|
482
615
|
|
|
483
|
-
this._openedWithFocusRing = this
|
|
616
|
+
this._openedWithFocusRing = this._overflow.hasAttribute('focus-ring');
|
|
484
617
|
|
|
485
618
|
this._menuElement.focus();
|
|
486
619
|
} else if (wasOpened) {
|
|
487
|
-
this
|
|
620
|
+
this._overflow.focus();
|
|
488
621
|
if (this._openedWithFocusRing) {
|
|
489
|
-
this
|
|
622
|
+
this._overflow.setAttribute('focus-ring', '');
|
|
490
623
|
}
|
|
491
624
|
}
|
|
492
|
-
this
|
|
625
|
+
this._overflow.setAttribute('aria-expanded', opened === true);
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
/** @private */
|
|
629
|
+
__overflowItemsChanged(items, oldItems) {
|
|
630
|
+
if (items || oldItems) {
|
|
631
|
+
this.$.overlay.requestContentUpdate();
|
|
632
|
+
}
|
|
493
633
|
}
|
|
494
634
|
|
|
495
635
|
/** @private */
|
|
@@ -55,24 +55,13 @@ registerStyles('vaadin-avatar-group-overlay', [overlay, menuOverlayCore, avatarG
|
|
|
55
55
|
});
|
|
56
56
|
|
|
57
57
|
registerStyles(
|
|
58
|
-
'vaadin-
|
|
58
|
+
'vaadin-item',
|
|
59
59
|
css`
|
|
60
|
-
|
|
60
|
+
:host([theme='avatar-group-item']) {
|
|
61
61
|
padding: var(--lumo-space-xs);
|
|
62
|
-
padding-
|
|
62
|
+
padding-inline-end: var(--lumo-space-m);
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
-
:host([dir='rtl']) [part='items'] ::slotted(vaadin-item[theme='avatar-group-item']) {
|
|
66
|
-
padding: var(--lumo-space-xs);
|
|
67
|
-
padding-left: var(--lumo-space-m);
|
|
68
|
-
}
|
|
69
|
-
`,
|
|
70
|
-
{ moduleId: 'lumo-avatar-group-list-box' },
|
|
71
|
-
);
|
|
72
|
-
|
|
73
|
-
registerStyles(
|
|
74
|
-
'vaadin-item',
|
|
75
|
-
css`
|
|
76
65
|
:host([theme='avatar-group-item']) [part='content'] {
|
|
77
66
|
display: flex;
|
|
78
67
|
align-items: center;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import '@vaadin/avatar/theme/lumo/vaadin-avatar.js';
|
|
2
2
|
import '@vaadin/item/theme/lumo/vaadin-item.js';
|
|
3
3
|
import '@vaadin/list-box/theme/lumo/vaadin-list-box.js';
|
|
4
|
-
import '@vaadin/
|
|
4
|
+
import '@vaadin/overlay/theme/lumo/vaadin-overlay.js';
|
|
5
5
|
import './vaadin-avatar-group-styles.js';
|
|
6
6
|
import '../../src/vaadin-avatar-group.js';
|
|
@@ -47,24 +47,13 @@ registerStyles('vaadin-avatar-group-overlay', [menuOverlay, avatarGroupOverlay],
|
|
|
47
47
|
});
|
|
48
48
|
|
|
49
49
|
registerStyles(
|
|
50
|
-
'vaadin-
|
|
50
|
+
'vaadin-item',
|
|
51
51
|
css`
|
|
52
|
-
|
|
52
|
+
:host([theme='avatar-group-item']) {
|
|
53
53
|
padding: 8px;
|
|
54
|
-
padding-
|
|
54
|
+
padding-inline-end: 24px;
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
-
:host([dir='rtl']) [part='items'] ::slotted(vaadin-item[theme='avatar-group-item']) {
|
|
58
|
-
padding: 8px;
|
|
59
|
-
padding-left: 24px;
|
|
60
|
-
}
|
|
61
|
-
`,
|
|
62
|
-
{ moduleId: 'material-avatar-group-list-box' },
|
|
63
|
-
);
|
|
64
|
-
|
|
65
|
-
registerStyles(
|
|
66
|
-
'vaadin-item',
|
|
67
|
-
css`
|
|
68
57
|
:host([theme='avatar-group-item']) [part='content'] {
|
|
69
58
|
display: flex;
|
|
70
59
|
align-items: center;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import '@vaadin/avatar/theme/material/vaadin-avatar.js';
|
|
2
2
|
import '@vaadin/item/theme/material/vaadin-item.js';
|
|
3
3
|
import '@vaadin/list-box/theme/material/vaadin-list-box.js';
|
|
4
|
-
import '@vaadin/
|
|
4
|
+
import '@vaadin/overlay/theme/material/vaadin-overlay.js';
|
|
5
5
|
import './vaadin-avatar-group-styles.js';
|
|
6
6
|
import '../../src/vaadin-avatar-group.js';
|
package/web-types.json
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json.schemastore.org/web-types",
|
|
3
3
|
"name": "@vaadin/avatar-group",
|
|
4
|
-
"version": "
|
|
4
|
+
"version": "24.0.0-alpha1",
|
|
5
5
|
"description-markup": "markdown",
|
|
6
6
|
"contributions": {
|
|
7
7
|
"html": {
|
|
8
8
|
"elements": [
|
|
9
9
|
{
|
|
10
10
|
"name": "vaadin-avatar-group",
|
|
11
|
-
"description": "`<vaadin-avatar-group>` is a Web Component providing avatar group displaying functionality.\n\nTo create the avatar group, first add the component to the page:\n\n```\n<vaadin-avatar-group></vaadin-avatar-group>\n```\n\nAnd then use [`items`](https://cdn.vaadin.com/vaadin-web-components/
|
|
11
|
+
"description": "`<vaadin-avatar-group>` is a Web Component providing avatar group displaying functionality.\n\nTo create the avatar group, first add the component to the page:\n\n```\n<vaadin-avatar-group></vaadin-avatar-group>\n```\n\nAnd then use [`items`](https://cdn.vaadin.com/vaadin-web-components/24.0.0-alpha1/#/elements/vaadin-avatar-group#property-items) property to initialize the structure:\n\n```\ndocument.querySelector('vaadin-avatar-group').items = [\n {name: 'John Doe'},\n {abbr: 'AB'}\n];\n```\n\n### Styling\n\nThe following shadow DOM parts are exposed for styling:\n\nPart name | Description\n----------- | ---------------\n`container` | The container element\n\nSee the [`<vaadin-avatar>`](https://cdn.vaadin.com/vaadin-web-components/24.0.0-alpha1/#/elements/vaadin-avatar) documentation for the available\nstate attributes and stylable shadow parts of avatar elements.\n\nSee [Styling Components](https://vaadin.com/docs/latest/styling/custom-theme/styling-components) documentation.\n\n### Internal components\n\nIn addition to `<vaadin-avatar-group>` itself, the following internal\ncomponents are themable:\n\n- `<vaadin-avatar-group-overlay>` - has the same API as [`<vaadin-overlay>`](https://cdn.vaadin.com/vaadin-web-components/24.0.0-alpha1/#/elements/vaadin-overlay).",
|
|
12
12
|
"attributes": [
|
|
13
13
|
{
|
|
14
14
|
"name": "max-items-visible",
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"properties": [
|
|
38
38
|
{
|
|
39
39
|
"name": "items",
|
|
40
|
-
"description": "An array containing the items which will be stamped as avatars.\n\nThe items objects allow to configure [`name`](https://cdn.vaadin.com/vaadin-web-components/
|
|
40
|
+
"description": "An array containing the items which will be stamped as avatars.\n\nThe items objects allow to configure [`name`](https://cdn.vaadin.com/vaadin-web-components/24.0.0-alpha1/#/elements/vaadin-avatar#property-name),\n[`abbr`](https://cdn.vaadin.com/vaadin-web-components/24.0.0-alpha1/#/elements/vaadin-avatar#property-abbr), [`img`](#/elements/vaadin-avatar#property-img)\nand [`colorIndex`](https://cdn.vaadin.com/vaadin-web-components/24.0.0-alpha1/#/elements/vaadin-avatar#property-colorIndex) properties on the\nstamped avatars.\n\n#### Example\n\n```js\ngroup.items = [\n {\n name: 'User name',\n img: 'url-to-image.png'\n },\n {\n abbr: 'JD',\n colorIndex: 1\n },\n];\n```",
|
|
41
41
|
"value": {
|
|
42
42
|
"type": [
|
|
43
43
|
"Array.<AvatarGroupItem>",
|
package/web-types.lit.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json.schemastore.org/web-types",
|
|
3
3
|
"name": "@vaadin/avatar-group",
|
|
4
|
-
"version": "
|
|
4
|
+
"version": "24.0.0-alpha1",
|
|
5
5
|
"description-markup": "markdown",
|
|
6
6
|
"framework": "lit",
|
|
7
7
|
"framework-config": {
|
|
@@ -16,12 +16,12 @@
|
|
|
16
16
|
"elements": [
|
|
17
17
|
{
|
|
18
18
|
"name": "vaadin-avatar-group",
|
|
19
|
-
"description": "`<vaadin-avatar-group>` is a Web Component providing avatar group displaying functionality.\n\nTo create the avatar group, first add the component to the page:\n\n```\n<vaadin-avatar-group></vaadin-avatar-group>\n```\n\nAnd then use [`items`](https://cdn.vaadin.com/vaadin-web-components/
|
|
19
|
+
"description": "`<vaadin-avatar-group>` is a Web Component providing avatar group displaying functionality.\n\nTo create the avatar group, first add the component to the page:\n\n```\n<vaadin-avatar-group></vaadin-avatar-group>\n```\n\nAnd then use [`items`](https://cdn.vaadin.com/vaadin-web-components/24.0.0-alpha1/#/elements/vaadin-avatar-group#property-items) property to initialize the structure:\n\n```\ndocument.querySelector('vaadin-avatar-group').items = [\n {name: 'John Doe'},\n {abbr: 'AB'}\n];\n```\n\n### Styling\n\nThe following shadow DOM parts are exposed for styling:\n\nPart name | Description\n----------- | ---------------\n`container` | The container element\n\nSee the [`<vaadin-avatar>`](https://cdn.vaadin.com/vaadin-web-components/24.0.0-alpha1/#/elements/vaadin-avatar) documentation for the available\nstate attributes and stylable shadow parts of avatar elements.\n\nSee [Styling Components](https://vaadin.com/docs/latest/styling/custom-theme/styling-components) documentation.\n\n### Internal components\n\nIn addition to `<vaadin-avatar-group>` itself, the following internal\ncomponents are themable:\n\n- `<vaadin-avatar-group-overlay>` - has the same API as [`<vaadin-overlay>`](https://cdn.vaadin.com/vaadin-web-components/24.0.0-alpha1/#/elements/vaadin-overlay).",
|
|
20
20
|
"extension": true,
|
|
21
21
|
"attributes": [
|
|
22
22
|
{
|
|
23
23
|
"name": ".items",
|
|
24
|
-
"description": "An array containing the items which will be stamped as avatars.\n\nThe items objects allow to configure [`name`](https://cdn.vaadin.com/vaadin-web-components/
|
|
24
|
+
"description": "An array containing the items which will be stamped as avatars.\n\nThe items objects allow to configure [`name`](https://cdn.vaadin.com/vaadin-web-components/24.0.0-alpha1/#/elements/vaadin-avatar#property-name),\n[`abbr`](https://cdn.vaadin.com/vaadin-web-components/24.0.0-alpha1/#/elements/vaadin-avatar#property-abbr), [`img`](#/elements/vaadin-avatar#property-img)\nand [`colorIndex`](https://cdn.vaadin.com/vaadin-web-components/24.0.0-alpha1/#/elements/vaadin-avatar#property-colorIndex) properties on the\nstamped avatars.\n\n#### Example\n\n```js\ngroup.items = [\n {\n name: 'User name',\n img: 'url-to-image.png'\n },\n {\n abbr: 'JD',\n colorIndex: 1\n },\n];\n```",
|
|
25
25
|
"value": {
|
|
26
26
|
"kind": "expression"
|
|
27
27
|
}
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @license
|
|
3
|
-
* Copyright (c) 2020 - 2022 Vaadin Ltd.
|
|
4
|
-
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
5
|
-
*/
|
|
6
|
-
import { ListBox } from '@vaadin/list-box/src/vaadin-list-box.js';
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* An element used internally by `<vaadin-avatar-group>`. Not intended to be used separately.
|
|
10
|
-
*
|
|
11
|
-
* @extends ListBox
|
|
12
|
-
* @private
|
|
13
|
-
*/
|
|
14
|
-
class AvatarGroupListBox extends ListBox {
|
|
15
|
-
static get is() {
|
|
16
|
-
return 'vaadin-avatar-group-list-box';
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
customElements.define(AvatarGroupListBox.is, AvatarGroupListBox);
|