Skip to content

Commit 430329c

Browse files
authored
refactor!: update user-tags overlay to use native popover (#9820)
1 parent c32d6bc commit 430329c

File tree

5 files changed

+71
-32
lines changed

5 files changed

+71
-32
lines changed

packages/field-highlighter/src/styles/vaadin-user-tags-overlay-core-styles.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ const userTagsOverlay = css`
1515
overflow: visible;
1616
}
1717
18-
::slotted([part='tags']) {
18+
[part='content'] {
1919
display: flex;
2020
flex-direction: column;
2121
align-items: flex-start;

packages/field-highlighter/src/vaadin-user-tags-overlay.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,22 @@ class UserTagsOverlay extends PositionMixin(
4545
</div>
4646
`;
4747
}
48+
49+
/**
50+
* @protected
51+
* @override
52+
*/
53+
_attachOverlay() {
54+
this.showPopover();
55+
}
56+
57+
/**
58+
* @protected
59+
* @override
60+
*/
61+
_detachOverlay() {
62+
this.hidePopover();
63+
}
4864
}
4965

5066
defineCustomElement(UserTagsOverlay);

packages/field-highlighter/src/vaadin-user-tags.js

Lines changed: 17 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -46,11 +46,15 @@ export class UserTags extends PolylitMixin(LitElement) {
4646
return html`
4747
<vaadin-user-tags-overlay
4848
id="overlay"
49+
popover="manual"
50+
exportparts="overlay:user-tags-overlay, content:user-tags-content"
4951
modeless
5052
.opened="${this.opened}"
5153
no-vertical-overlap
5254
@vaadin-overlay-open="${this._onOverlayOpen}"
53-
></vaadin-user-tags-overlay>
55+
>
56+
<slot></slot>
57+
</vaadin-user-tags-overlay>
5458
`;
5559
}
5660

@@ -137,7 +141,8 @@ export class UserTags extends PolylitMixin(LitElement) {
137141

138142
/** @protected */
139143
get wrapper() {
140-
return this.$.overlay.querySelector('[part="tags"]');
144+
// Used by Collaboration Kit util
145+
return this;
141146
}
142147

143148
/** @protected */
@@ -162,15 +167,8 @@ export class UserTags extends PolylitMixin(LitElement) {
162167
ready() {
163168
super.ready();
164169

165-
this.$.overlay.renderer = (root) => {
166-
if (!root.firstChild) {
167-
const tags = document.createElement('div');
168-
tags.setAttribute('part', 'tags');
169-
root.appendChild(tags);
170-
}
171-
};
172-
173-
this.$.overlay.requestContentUpdate();
170+
// Export user tags overlay parts for styling
171+
this.setAttribute('exportparts', 'user-tags-overlay, user-tags-content');
174172
}
175173

176174
/** @private */
@@ -222,14 +220,15 @@ export class UserTags extends PolylitMixin(LitElement) {
222220

223221
createUserTag(user) {
224222
const tag = document.createElement('vaadin-user-tag');
223+
tag.setAttribute('part', 'user-tag');
225224
tag.name = user.name;
226225
tag.uid = user.id;
227226
tag.colorIndex = user.colorIndex;
228227
return tag;
229228
}
230229

231230
getTagForUser(user) {
232-
return Array.from(this.wrapper.children).find((tag) => tag.uid === user.id);
231+
return Array.from(this.children).find((tag) => tag.uid === user.id);
233232
}
234233

235234
getChangedTags(addedUsers, removedUsers) {
@@ -239,21 +238,19 @@ export class UserTags extends PolylitMixin(LitElement) {
239238
}
240239

241240
applyTagsStart({ added, removed }) {
242-
const wrapper = this.wrapper;
243241
removed.forEach((tag) => {
244242
if (tag) {
245243
tag.classList.add('removing');
246244
tag.classList.remove('show');
247245
}
248246
});
249-
added.forEach((tag) => wrapper.insertBefore(tag, wrapper.firstChild));
247+
added.forEach((tag) => this.insertBefore(tag, this.firstChild));
250248
}
251249

252250
applyTagsEnd({ added, removed }) {
253-
const wrapper = this.wrapper;
254251
removed.forEach((tag) => {
255-
if (tag && tag.parentNode === wrapper) {
256-
wrapper.removeChild(tag);
252+
if (tag && tag.parentNode === this) {
253+
this.removeChild(tag);
257254
}
258255
});
259256
added.forEach((tag) => tag && tag.classList.add('show'));
@@ -329,7 +326,7 @@ export class UserTags extends PolylitMixin(LitElement) {
329326
/** @private */
330327
_onOverlayOpen() {
331328
// Animate all tags except removing ones
332-
Array.from(this.wrapper.children).forEach((tag) => {
329+
Array.from(this.children).forEach((tag) => {
333330
if (!tag.classList.contains('removing')) {
334331
tag.classList.add('show');
335332
}
@@ -338,17 +335,16 @@ export class UserTags extends PolylitMixin(LitElement) {
338335

339336
flashTags(added) {
340337
this.flashing = true;
341-
const wrapper = this.wrapper;
342338

343339
// Hide existing tags
344-
const hidden = Array.from(wrapper.children);
340+
const hidden = Array.from(this.children);
345341
hidden.forEach((tag) => {
346342
tag.style.display = 'none';
347343
});
348344

349345
// Render new tags
350346
added.forEach((tag) => {
351-
wrapper.insertBefore(tag, wrapper.firstChild);
347+
this.insertBefore(tag, this.firstChild);
352348
});
353349

354350
this.flashPromise = new Promise((resolve) => {

packages/field-highlighter/test/user-tags.test.js

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { expect } from '@vaadin/chai-plugins';
2-
import { fixtureSync, nextFrame, oneEvent } from '@vaadin/testing-helpers';
2+
import { fixtureSync, nextFrame, nextRender, oneEvent } from '@vaadin/testing-helpers';
33
import sinon from 'sinon';
44
import './test-styles.test.js';
55
import '@vaadin/text-field/src/vaadin-text-field.js';
@@ -20,8 +20,7 @@ describe('user-tags', () => {
2020
let wrapper;
2121

2222
const getTags = () => {
23-
const { overlay } = wrapper.$;
24-
return overlay.querySelectorAll('vaadin-user-tag');
23+
return wrapper.querySelectorAll('vaadin-user-tag');
2524
};
2625

2726
const addUser = (user) => {
@@ -60,10 +59,13 @@ describe('user-tags', () => {
6059
it('should replace user tags when replacing users', async () => {
6160
setUsers([user1, user2]);
6261
await wrapper.flashPromise;
62+
expect(getTags()).to.have.lengthOf(2);
63+
64+
await nextRender();
65+
6366
setUsers([user3]);
6467
await wrapper.flashPromise;
65-
const tags = getTags();
66-
expect(tags).to.have.lengthOf(1);
68+
expect(getTags()).to.have.lengthOf(1);
6769
});
6870
});
6971

@@ -308,4 +310,32 @@ describe('user-tags', () => {
308310
});
309311
});
310312
});
313+
314+
describe('exportparts', () => {
315+
let overlay;
316+
317+
beforeEach(() => {
318+
field = fixtureSync(`<vaadin-text-field></vaadin-text-field>`);
319+
FieldHighlighter.init(field);
320+
wrapper = field.shadowRoot.querySelector('vaadin-user-tags');
321+
overlay = wrapper.$.overlay;
322+
});
323+
324+
it('should export all overlay parts for styling', () => {
325+
const overlayParts = [...overlay.shadowRoot.querySelectorAll('[part]')].map((el) => el.getAttribute('part'));
326+
const overlayExportParts = overlay.getAttribute('exportparts').split(', ');
327+
const hostExportParts = wrapper.getAttribute('exportparts').split(', ');
328+
329+
overlayParts.forEach((part) => {
330+
expect(overlayExportParts).to.include(`${part}:user-tags-${part}`);
331+
expect(hostExportParts).to.include(`user-tags-${part}`);
332+
});
333+
});
334+
335+
it('should set part="user-tag" on the user tag elements', () => {
336+
getTags().forEach((tag) => {
337+
expect(tag.getAttribute('part')).to.equal('user-tag');
338+
});
339+
});
340+
});
311341
});

packages/vaadin-lumo-styles/src/components/user-tags-overlay.css

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,21 +15,18 @@
1515
will-change: opacity, transform;
1616
}
1717

18-
::slotted([part='tags']) {
18+
[part='content'] {
1919
display: flex;
2020
flex-direction: column;
2121
align-items: flex-start;
22+
padding: 0;
2223
}
2324

2425
:host([dir='rtl']) [part='overlay'] {
2526
left: auto;
2627
right: -4px;
2728
}
2829

29-
[part='content'] {
30-
padding: 0;
31-
}
32-
3330
:host([opening]),
3431
:host([closing]) {
3532
animation: 0.14s user-tags-overlay-dummy-animation;

0 commit comments

Comments
 (0)