@vaadin/field-highlighter 23.0.9 → 23.0.12

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vaadin/field-highlighter",
3
- "version": "23.0.9",
3
+ "version": "23.0.12",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -34,27 +34,27 @@
34
34
  ],
35
35
  "dependencies": {
36
36
  "@polymer/polymer": "^3.0.0",
37
- "@vaadin/component-base": "^23.0.9",
38
- "@vaadin/vaadin-lumo-styles": "^23.0.9",
39
- "@vaadin/vaadin-material-styles": "^23.0.9",
40
- "@vaadin/vaadin-overlay": "^23.0.9",
41
- "@vaadin/vaadin-themable-mixin": "^23.0.9",
37
+ "@vaadin/component-base": "^23.0.12",
38
+ "@vaadin/vaadin-lumo-styles": "^23.0.12",
39
+ "@vaadin/vaadin-material-styles": "^23.0.12",
40
+ "@vaadin/vaadin-overlay": "^23.0.12",
41
+ "@vaadin/vaadin-themable-mixin": "^23.0.12",
42
42
  "lit": "^2.0.0"
43
43
  },
44
44
  "devDependencies": {
45
45
  "@esm-bundle/chai": "^4.3.4",
46
- "@vaadin/checkbox": "^23.0.9",
47
- "@vaadin/combo-box": "^23.0.9",
48
- "@vaadin/date-picker": "^23.0.9",
49
- "@vaadin/date-time-picker": "^23.0.9",
50
- "@vaadin/item": "^23.0.9",
51
- "@vaadin/list-box": "^23.0.9",
52
- "@vaadin/radio-group": "^23.0.9",
53
- "@vaadin/select": "^23.0.9",
46
+ "@vaadin/checkbox": "^23.0.12",
47
+ "@vaadin/combo-box": "^23.0.12",
48
+ "@vaadin/date-picker": "^23.0.12",
49
+ "@vaadin/date-time-picker": "^23.0.12",
50
+ "@vaadin/item": "^23.0.12",
51
+ "@vaadin/list-box": "^23.0.12",
52
+ "@vaadin/radio-group": "^23.0.12",
53
+ "@vaadin/select": "^23.0.12",
54
54
  "@vaadin/testing-helpers": "^0.3.2",
55
- "@vaadin/text-field": "^23.0.9",
56
- "@vaadin/time-picker": "^23.0.9",
55
+ "@vaadin/text-field": "^23.0.12",
56
+ "@vaadin/time-picker": "^23.0.12",
57
57
  "sinon": "^9.2.1"
58
58
  },
59
- "gitHead": "4d687bdd48ba78d55f3371a78b70818e4dfca1a3"
59
+ "gitHead": "717908c222c1e241259e30b4144cd5ba32734819"
60
60
  }
@@ -109,8 +109,8 @@ export class ComponentObserver {
109
109
  new CustomEvent(`vaadin-highlight-${action}`, {
110
110
  bubbles: true,
111
111
  composed: true,
112
- detail: { fieldIndex: this.getFieldIndex(field) }
113
- })
112
+ detail: { fieldIndex: this.getFieldIndex(field) },
113
+ }),
114
114
  );
115
115
  }
116
116
 
@@ -54,8 +54,8 @@ export class FieldOutline extends ThemableMixin(DirMixin(PolymerElement)) {
54
54
  user: {
55
55
  type: Object,
56
56
  value: null,
57
- observer: '_userChanged'
58
- }
57
+ observer: '_userChanged',
58
+ },
59
59
  };
60
60
  }
61
61
 
@@ -66,14 +66,14 @@ export class UserTag extends ThemableMixin(DirMixin(PolymerElement)) {
66
66
  * Name of the user.
67
67
  */
68
68
  name: {
69
- type: String
69
+ type: String,
70
70
  },
71
71
 
72
72
  /**
73
73
  * Id of the user.
74
74
  */
75
75
  uid: {
76
- type: String
76
+ type: String,
77
77
  },
78
78
 
79
79
  /**
@@ -81,8 +81,8 @@ export class UserTag extends ThemableMixin(DirMixin(PolymerElement)) {
81
81
  */
82
82
  colorIndex: {
83
83
  type: Number,
84
- observer: '_colorIndexChanged'
85
- }
84
+ observer: '_colorIndexChanged',
85
+ },
86
86
  };
87
87
  }
88
88
 
@@ -114,9 +114,9 @@ export class UserTag extends ThemableMixin(DirMixin(PolymerElement)) {
114
114
  bubbles: true,
115
115
  composed: true,
116
116
  detail: {
117
- name: this.name
118
- }
119
- })
117
+ name: this.name,
118
+ },
119
+ }),
120
120
  );
121
121
  }
122
122
  }
@@ -4,17 +4,15 @@
4
4
  * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
5
  */
6
6
  import { OverlayElement } from '@vaadin/vaadin-overlay/src/vaadin-overlay.js';
7
+ import { PositionMixin } from '@vaadin/vaadin-overlay/src/vaadin-overlay-position-mixin.js';
7
8
  import { css, registerStyles } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
8
9
 
9
10
  registerStyles(
10
11
  'vaadin-user-tags-overlay',
11
12
  css`
12
13
  :host {
13
- align-items: stretch;
14
- justify-content: flex-start;
15
14
  background: transparent;
16
15
  box-shadow: none;
17
- bottom: auto;
18
16
  }
19
17
 
20
18
  [part='overlay'] {
@@ -42,14 +40,6 @@ registerStyles(
42
40
  padding: 0;
43
41
  }
44
42
 
45
- :host([dir='rtl']) {
46
- left: auto;
47
- }
48
-
49
- :host(:not([dir='rtl'])) {
50
- right: auto;
51
- }
52
-
53
43
  :host([opening]),
54
44
  :host([closing]) {
55
45
  animation: 0.14s user-tags-overlay-dummy-animation;
@@ -64,7 +54,7 @@ registerStyles(
64
54
  opacity: 1;
65
55
  }
66
56
  }
67
- `
57
+ `,
68
58
  );
69
59
 
70
60
  /**
@@ -73,7 +63,7 @@ registerStyles(
73
63
  * @extends OverlayElement
74
64
  * @private
75
65
  */
76
- class UserTagsOverlay extends OverlayElement {
66
+ class UserTagsOverlay extends PositionMixin(OverlayElement) {
77
67
  static get is() {
78
68
  return 'vaadin-user-tags-overlay';
79
69
  }
@@ -10,9 +10,6 @@ import { html, PolymerElement } from '@polymer/polymer/polymer-element.js';
10
10
  import { timeOut } from '@vaadin/component-base/src/async.js';
11
11
  import { Debouncer } from '@vaadin/component-base/src/debounce.js';
12
12
 
13
- const DURATION = 200;
14
- const DELAY = 2000;
15
-
16
13
  const listenOnce = (elem, type) => {
17
14
  return new Promise((resolve) => {
18
15
  const listener = () => {
@@ -45,6 +42,7 @@ export class UserTags extends PolymerElement {
45
42
  id="overlay"
46
43
  modeless
47
44
  opened="[[opened]]"
45
+ no-vertical-overlap
48
46
  on-vaadin-overlay-open="_onOverlayOpen"
49
47
  ></vaadin-user-tags-overlay>
50
48
  `;
@@ -59,7 +57,7 @@ export class UserTags extends PolymerElement {
59
57
  hasFocus: {
60
58
  type: Boolean,
61
59
  value: false,
62
- observer: '_hasFocusChanged'
60
+ observer: '_hasFocusChanged',
63
61
  },
64
62
 
65
63
  /**
@@ -68,7 +66,6 @@ export class UserTags extends PolymerElement {
68
66
  opened: {
69
67
  type: Boolean,
70
68
  value: false,
71
- observer: '_openedChanged'
72
69
  },
73
70
 
74
71
  /**
@@ -77,14 +74,15 @@ export class UserTags extends PolymerElement {
77
74
  */
78
75
  flashing: {
79
76
  type: Boolean,
80
- value: false
77
+ value: false,
81
78
  },
82
79
 
83
80
  /**
84
81
  * A target element that the overlay is positioned to.
85
82
  */
86
83
  target: {
87
- type: Object
84
+ type: Object,
85
+ observer: '__targetChanged',
88
86
  },
89
87
 
90
88
  /**
@@ -92,37 +90,63 @@ export class UserTags extends PolymerElement {
92
90
  */
93
91
  users: {
94
92
  type: Array,
95
- value: () => []
93
+ value: () => [],
94
+ },
95
+
96
+ duration: {
97
+ type: Number,
98
+ value: 200,
99
+ },
100
+
101
+ delay: {
102
+ type: Number,
103
+ value: 2000,
96
104
  },
97
105
 
98
106
  /** @private */
99
- _flashQueue: {
107
+ __flashQueue: {
100
108
  type: Array,
101
- value: () => []
102
- }
109
+ value: () => [],
110
+ },
111
+
112
+ /** @private */
113
+ __isTargetVisible: {
114
+ type: Boolean,
115
+ value: false,
116
+ },
103
117
  };
104
118
  }
105
119
 
106
120
  constructor() {
107
121
  super();
108
- this._boundSetPosition = this._debounceSetPosition.bind(this);
122
+
123
+ this.__targetVisibilityObserver = new IntersectionObserver(
124
+ ([entry]) => {
125
+ this.__onTargetVisibilityChange(entry.isIntersecting);
126
+ },
127
+ { threshold: 1 },
128
+ );
109
129
  }
110
130
 
111
131
  /** @protected */
112
132
  connectedCallback() {
113
133
  super.connectedCallback();
114
- window.addEventListener('resize', this._boundSetPosition);
115
- window.addEventListener('scroll', this._boundSetPosition);
134
+
135
+ if (this.target) {
136
+ this.__targetVisibilityObserver.observe(this.target);
137
+ }
116
138
  }
117
139
 
118
140
  /** @protected */
119
141
  disconnectedCallback() {
120
142
  super.disconnectedCallback();
121
- window.removeEventListener('resize', this._boundSetPosition);
122
- window.removeEventListener('scroll', this._boundSetPosition);
123
143
  this.opened = false;
144
+ if (this.target) {
145
+ this.__targetVisibilityObserver.unobserve(this.target);
146
+ }
124
147
  }
125
148
 
149
+ /** @protected */
126
150
  ready() {
127
151
  super.ready();
128
152
 
@@ -138,14 +162,42 @@ export class UserTags extends PolymerElement {
138
162
  }
139
163
 
140
164
  /** @private */
141
- _debounceSetPosition() {
142
- this._debouncePosition = Debouncer.debounce(this._debouncePosition, timeOut.after(16), () => this._setPosition());
165
+ __onTargetVisibilityChange(isVisible) {
166
+ this.__isTargetVisible = isVisible;
167
+
168
+ // Open the overlay and run the flashing animation for the user tags
169
+ // that have been enqueued (if any) during a `.setUsers()` call
170
+ // because the field was not visible at that point.
171
+ if (isVisible && this.__flashQueue.length > 0 && !this.flashing) {
172
+ this.flashTags(this.__flashQueue.shift());
173
+ return;
174
+ }
175
+
176
+ // Open the overlay when the field is visible and focused.
177
+ // - opens the overlay in the case it was not opened during a `.show()` call because the field was not visible at that point.
178
+ // - re-opens the overlay in the case it was closed because the focused field became not visible for a while (see the below check).
179
+ if (isVisible && this.hasFocus) {
180
+ this.opened = true;
181
+ return;
182
+ }
183
+
184
+ // Close the overlay when the field is not visible.
185
+ // The focused field will be re-opened once it becomes visible again (see the above check).
186
+ if (!isVisible && this.opened) {
187
+ this.opened = false;
188
+ }
143
189
  }
144
190
 
145
191
  /** @private */
146
- _openedChanged(opened) {
147
- if (opened) {
148
- this._setPosition();
192
+ __targetChanged(newTarget, oldTarget) {
193
+ this.$.overlay.positionTarget = newTarget;
194
+
195
+ if (oldTarget) {
196
+ this.__targetVisibilityObserver.unobserve(oldTarget);
197
+ }
198
+
199
+ if (newTarget) {
200
+ this.__targetVisibilityObserver.observe(newTarget);
149
201
  }
150
202
  }
151
203
 
@@ -156,34 +208,6 @@ export class UserTags extends PolymerElement {
156
208
  }
157
209
  }
158
210
 
159
- /**
160
- * Set position of the user tags overlay.
161
- * TODO: use PositionMixin instead.
162
- *
163
- * @private
164
- */
165
- _setPosition() {
166
- if (!this.opened) {
167
- return;
168
- }
169
-
170
- const targetRect = this.target.getBoundingClientRect();
171
-
172
- const overlayRect = this.$.overlay.getBoundingClientRect();
173
-
174
- this._translateX =
175
- this.getAttribute('dir') === 'rtl'
176
- ? targetRect.right - overlayRect.right + (this._translateX || 0)
177
- : targetRect.left - overlayRect.left + (this._translateX || 0);
178
- this._translateY = targetRect.top - overlayRect.top + (this._translateY || 0) + targetRect.height;
179
-
180
- const devicePixelRatio = window.devicePixelRatio || 1;
181
- this._translateX = Math.round(this._translateX * devicePixelRatio) / devicePixelRatio;
182
- this._translateY = Math.round(this._translateY * devicePixelRatio) / devicePixelRatio;
183
-
184
- this.$.overlay.style.transform = `translate3d(${this._translateX}px, ${this._translateY}px, 0)`;
185
- }
186
-
187
211
  get wrapper() {
188
212
  return this.$.overlay.content.querySelector('[part="tags"]');
189
213
  }
@@ -264,13 +288,13 @@ export class UserTags extends PolymerElement {
264
288
 
265
289
  const changedTags = this.getChangedTags(addedUsers, removedUsers);
266
290
 
267
- // check if flash queue contains pending tags for removed users
268
- if (this._flashQueue.length > 0) {
291
+ // Check if flash queue contains pending tags for removed users
292
+ if (this.__flashQueue.length > 0) {
269
293
  for (let i = 0; i < removedUsers.length; i++) {
270
294
  if (changedTags.removed[i] === null) {
271
- for (let j = 0; j < this._flashQueue.length; j++) {
272
- if (this._flashQueue[j].some((tag) => tag.uid === removedUsers[i].id)) {
273
- this.splice('_flashQueue', i, 1);
295
+ for (let j = 0; j < this.__flashQueue.length; j++) {
296
+ if (this.__flashQueue[j].some((tag) => tag.uid === removedUsers[i].id)) {
297
+ this.splice('__flashQueue', i, 1);
274
298
  }
275
299
  }
276
300
  }
@@ -279,16 +303,25 @@ export class UserTags extends PolymerElement {
279
303
 
280
304
  if (this.opened && this.hasFocus) {
281
305
  this.updateTags(users, changedTags);
282
- } else if (addedUsers.length && document.visibilityState !== 'hidden') {
306
+ } else if (addedUsers.length > 0 && document.visibilityState !== 'hidden') {
283
307
  // Avoid adding to queue if window is not visible.
284
- const tags = changedTags.added;
285
- if (this.flashing) {
286
- // schedule next flash later
287
- this.push('_flashQueue', tags);
308
+
309
+ const addedTags = changedTags.added;
310
+ const removedTags = changedTags.removed;
311
+
312
+ // Only sync the removed user tags.
313
+ // The added tags are handled by the `flashTags` method.
314
+ this.updateTagsSync(users, {
315
+ added: [],
316
+ removed: removedTags,
317
+ });
318
+
319
+ if (this.flashing || !this.__isTargetVisible) {
320
+ // Schedule next flash later
321
+ this.push('__flashQueue', addedTags);
288
322
  } else {
289
- this.flashTags(tags);
323
+ this.flashTags(addedTags);
290
324
  }
291
- this.set('users', users);
292
325
  } else {
293
326
  this.updateTagsSync(users, changedTags);
294
327
  }
@@ -319,36 +352,40 @@ export class UserTags extends PolymerElement {
319
352
 
320
353
  this.flashPromise = new Promise((resolve) => {
321
354
  listenOnce(this.$.overlay, 'vaadin-overlay-open').then(() => {
322
- this._debounceFlashStart = Debouncer.debounce(this._debounceFlashStart, timeOut.after(DURATION + DELAY), () => {
323
- // animate disappearing
324
- if (!this.hasFocus) {
325
- added.forEach((tag) => tag.classList.remove('show'));
326
- }
327
- this._debounceFlashEnd = Debouncer.debounce(this._debounceFlashEnd, timeOut.after(DURATION), () => {
328
- // show all tags
329
- const finishFlash = () => {
330
- hidden.forEach((tag) => (tag.style.display = 'block'));
331
- this.flashing = false;
332
- resolve();
333
- };
334
-
335
- if (this.hasFocus) {
336
- finishFlash();
337
- } else {
338
- // wait for overlay closing animation to complete
339
- listenOnce(this.$.overlay, 'animationend').then(() => {
340
- finishFlash();
341
- });
342
-
343
- this.opened = false;
355
+ this._debounceFlashStart = Debouncer.debounce(
356
+ this._debounceFlashStart,
357
+ timeOut.after(this.duration + this.delay),
358
+ () => {
359
+ // Animate disappearing
360
+ if (!this.hasFocus) {
361
+ added.forEach((tag) => tag.classList.remove('show'));
344
362
  }
345
- });
346
- });
363
+ this._debounceFlashEnd = Debouncer.debounce(this._debounceFlashEnd, timeOut.after(this.duration), () => {
364
+ // Show all tags
365
+ const finishFlash = () => {
366
+ hidden.forEach((tag) => (tag.style.display = 'block'));
367
+ this.flashing = false;
368
+ resolve();
369
+ };
370
+
371
+ if (this.hasFocus) {
372
+ finishFlash();
373
+ } else {
374
+ // Wait for overlay closing animation to complete
375
+ listenOnce(this.$.overlay, 'animationend').then(() => {
376
+ finishFlash();
377
+ });
378
+
379
+ this.opened = false;
380
+ }
381
+ });
382
+ },
383
+ );
347
384
  });
348
385
  }).then(() => {
349
- if (this._flashQueue.length > 0) {
350
- const tags = this._flashQueue[0];
351
- this.splice('_flashQueue', 0, 1);
386
+ if (this.__flashQueue.length > 0) {
387
+ const tags = this.__flashQueue[0];
388
+ this.splice('__flashQueue', 0, 1);
352
389
  this.flashTags(tags);
353
390
  }
354
391
  });
@@ -365,7 +402,7 @@ export class UserTags extends PolymerElement {
365
402
  updateTags(users, changed) {
366
403
  this.applyTagsStart(changed);
367
404
 
368
- this._debounceRender = Debouncer.debounce(this._debounceRender, timeOut.after(DURATION), () => {
405
+ this._debounceRender = Debouncer.debounce(this._debounceRender, timeOut.after(this.duration), () => {
369
406
  this.set('users', users);
370
407
 
371
408
  this.applyTagsEnd(changed);
@@ -384,7 +421,9 @@ export class UserTags extends PolymerElement {
384
421
 
385
422
  show() {
386
423
  this.hasFocus = true;
387
- this.opened = true;
424
+ if (this.__isTargetVisible) {
425
+ this.opened = true;
426
+ }
388
427
  }
389
428
 
390
429
  hide() {
@@ -41,5 +41,5 @@ registerStyles(
41
41
  box-shadow: inset 0 0 0 2px var(--_active-user-color);
42
42
  }
43
43
  `,
44
- { moduleId: 'lumo-field-outline' }
44
+ { moduleId: 'lumo-field-outline' },
45
45
  );
@@ -37,8 +37,8 @@ registerStyles(
37
37
  }
38
38
  `,
39
39
  {
40
- moduleId: 'lumo-user-tags-overlay'
41
- }
40
+ moduleId: 'lumo-user-tags-overlay',
41
+ },
42
42
  );
43
43
 
44
44
  registerStyles(
@@ -60,5 +60,5 @@ registerStyles(
60
60
  min-width: calc(var(--lumo-line-height-xs) * 1em + 0.45em);
61
61
  }
62
62
  `,
63
- { moduleId: 'lumo-user-tag' }
63
+ { moduleId: 'lumo-user-tag' },
64
64
  );
@@ -3,5 +3,6 @@
3
3
  * Copyright (c) 2021 - 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 '@vaadin/vaadin-overlay/theme/lumo/vaadin-overlay.js';
6
7
  import './vaadin-user-tags-styles.js';
7
8
  import '../../src/vaadin-user-tags.js';
@@ -39,5 +39,5 @@ registerStyles(
39
39
  box-shadow: inset 0 0 0 2px var(--_active-user-color);
40
40
  }
41
41
  `,
42
- { moduleId: 'material-field-outline' }
42
+ { moduleId: 'material-field-outline' },
43
43
  );
@@ -27,5 +27,5 @@ registerStyles(
27
27
  min-width: 1.75em;
28
28
  }
29
29
  `,
30
- { moduleId: 'material-user-tag' }
30
+ { moduleId: 'material-user-tag' },
31
31
  );
@@ -3,5 +3,6 @@
3
3
  * Copyright (c) 2021 - 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 '@vaadin/vaadin-overlay/theme/material/vaadin-overlay.js';
6
7
  import './vaadin-user-tags-styles.js';
7
8
  import '../../src/vaadin-user-tags.js';