@vaadin/overlay 24.4.0-rc2 → 24.5.0-alpha2

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/overlay",
3
- "version": "24.4.0-rc2",
3
+ "version": "24.5.0-alpha2",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -36,11 +36,11 @@
36
36
  "dependencies": {
37
37
  "@open-wc/dedupe-mixin": "^1.3.0",
38
38
  "@polymer/polymer": "^3.0.0",
39
- "@vaadin/a11y-base": "24.4.0-rc2",
40
- "@vaadin/component-base": "24.4.0-rc2",
41
- "@vaadin/vaadin-lumo-styles": "24.4.0-rc2",
42
- "@vaadin/vaadin-material-styles": "24.4.0-rc2",
43
- "@vaadin/vaadin-themable-mixin": "24.4.0-rc2",
39
+ "@vaadin/a11y-base": "24.5.0-alpha2",
40
+ "@vaadin/component-base": "24.5.0-alpha2",
41
+ "@vaadin/vaadin-lumo-styles": "24.5.0-alpha2",
42
+ "@vaadin/vaadin-material-styles": "24.5.0-alpha2",
43
+ "@vaadin/vaadin-themable-mixin": "24.5.0-alpha2",
44
44
  "lit": "^3.0.0"
45
45
  },
46
46
  "devDependencies": {
@@ -48,5 +48,5 @@
48
48
  "@vaadin/testing-helpers": "^0.6.0",
49
49
  "sinon": "^13.0.2"
50
50
  },
51
- "gitHead": "ea3d99e8cf67a337e959d5cab849f80464c7c7e5"
51
+ "gitHead": "403f153bf4351f220cb6172485a0575ddf0d0fba"
52
52
  }
@@ -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 { getAncestorRootNodes } from '@vaadin/component-base/src/dom-utils.js';
7
+ import { observeMove } from './vaadin-overlay-utils.js';
7
8
 
8
9
  const PROP_NAMES_VERTICAL = {
9
10
  start: 'top',
@@ -153,6 +154,12 @@ export const PositionMixin = (superClass) =>
153
154
  this.__positionTargetAncestorRootNodes.forEach((node) => {
154
155
  node.addEventListener('scroll', this.__onScroll, true);
155
156
  });
157
+
158
+ if (this.positionTarget) {
159
+ this.__observePositionTargetMove = observeMove(this.positionTarget, () => {
160
+ this._updatePosition();
161
+ });
162
+ }
156
163
  }
157
164
 
158
165
  /** @private */
@@ -166,6 +173,11 @@ export const PositionMixin = (superClass) =>
166
173
  });
167
174
  this.__positionTargetAncestorRootNodes = null;
168
175
  }
176
+
177
+ if (this.__observePositionTargetMove) {
178
+ this.__observePositionTargetMove();
179
+ this.__observePositionTargetMove = null;
180
+ }
169
181
  }
170
182
 
171
183
  /** @private */
@@ -0,0 +1,13 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2024 Vaadin Ltd.
4
+ * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
+ */
6
+
7
+ /**
8
+ * Observe moving an element around on a page.
9
+ *
10
+ * Based on the idea from https://samthor.au/2021/observing-dom/ as implemented in Floating UI
11
+ * https://github.com/floating-ui/floating-ui/blob/58ed169/packages/dom/src/autoUpdate.ts#L45
12
+ */
13
+ export function observeMove(element: HTMLElement, callback: () => void): () => void;
@@ -0,0 +1,89 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2024 Vaadin Ltd.
4
+ * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
+ */
6
+
7
+ /**
8
+ * Observe moving an element around on a page.
9
+ *
10
+ * Based on the idea from https://samthor.au/2021/observing-dom/ as implemented in Floating UI
11
+ * https://github.com/floating-ui/floating-ui/blob/58ed169/packages/dom/src/autoUpdate.ts#L45
12
+ *
13
+ * @param {HTMLElement} element
14
+ * @param {Function} callback
15
+ * @return {Function}
16
+ */
17
+ export function observeMove(element, callback) {
18
+ let io = null;
19
+
20
+ const root = document.documentElement;
21
+
22
+ function cleanup() {
23
+ io && io.disconnect();
24
+ io = null;
25
+ }
26
+
27
+ function refresh(skip = false, threshold = 1) {
28
+ cleanup();
29
+
30
+ const { left, top, width, height } = element.getBoundingClientRect();
31
+
32
+ if (!skip) {
33
+ callback();
34
+ }
35
+
36
+ if (!width || !height) {
37
+ return;
38
+ }
39
+
40
+ const insetTop = Math.floor(top);
41
+ const insetRight = Math.floor(root.clientWidth - (left + width));
42
+ const insetBottom = Math.floor(root.clientHeight - (top + height));
43
+ const insetLeft = Math.floor(left);
44
+
45
+ const rootMargin = `${-insetTop}px ${-insetRight}px ${-insetBottom}px ${-insetLeft}px`;
46
+
47
+ const options = {
48
+ rootMargin,
49
+ threshold: Math.max(0, Math.min(1, threshold)) || 1,
50
+ };
51
+
52
+ let isFirstUpdate = true;
53
+
54
+ function handleObserve(entries) {
55
+ let ratio = entries[0].intersectionRatio;
56
+
57
+ if (ratio !== threshold) {
58
+ if (!isFirstUpdate) {
59
+ return refresh();
60
+ }
61
+
62
+ // It's possible for the watched element to not be at perfect 1.0 visibility when we create
63
+ // the IntersectionObserver. This has a couple of causes:
64
+ // - elements being on partial pixels
65
+ // - elements being hidden offscreen (e.g., <html> has `overflow: hidden`)
66
+ // - delays: if your DOM change occurs due to e.g., page resize, you can see elements
67
+ // behind their actual position
68
+ //
69
+ // In all of these cases, refresh but with this lower ratio of threshold. When the element
70
+ // moves beneath _that_ new value, the user will get notified.
71
+ if (ratio === 0.0) {
72
+ ratio = 0.0000001; // Just needs to be non-zero
73
+ }
74
+
75
+ refresh(false, ratio);
76
+ }
77
+
78
+ isFirstUpdate = false;
79
+ }
80
+
81
+ io = new IntersectionObserver(handleObserve, options);
82
+
83
+ io.observe(element);
84
+ }
85
+
86
+ refresh(true);
87
+
88
+ return cleanup;
89
+ }