@brightspace-ui/core 2.68.0 → 2.68.1

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.
@@ -2,6 +2,7 @@ import '../colors/colors.js';
2
2
  import '../../helpers/requestIdleCallback.js';
3
3
  import { css, html, LitElement } from 'lit';
4
4
  import { getBoundingAncestor, getComposedParent } from '../../helpers/dom.js';
5
+ import { getLegacyOffsetParent } from '../../helpers/offsetParent-legacy.js';
5
6
  import { RtlMixin } from '../../mixins/rtl-mixin.js';
6
7
  import { styleMap } from 'lit/directives/style-map.js';
7
8
 
@@ -224,7 +225,7 @@ class FloatingButtons extends RtlMixin(LitElement) {
224
225
  _getBoundingAncestor() {
225
226
 
226
227
  const boundingAncestor = getBoundingAncestor(this);
227
- const offsetParent = this.offsetParent;
228
+ const offsetParent = getLegacyOffsetParent(this);
228
229
  if (!offsetParent) {
229
230
  return null;
230
231
  }
package/helpers/README.md CHANGED
@@ -171,6 +171,19 @@ element.addEventListener('d2l-gesture-swipe', (e) => {
171
171
  });
172
172
  ```
173
173
 
174
+ ## offsetParent-legacy
175
+
176
+ A ponyfill for [offsetParent](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/offsetParent) for "legacy" `offsetParent` behaviour, which will include any ancestor shadow DOMs when searching for the closest positioned ancestor. The native browser behaviour was changed in 2022 to not leak nodes within a shadow tree.
177
+
178
+ To use the ponyfill, import `getLegacyOffsetParent` (and/or `getLegacyOffsetTop`, `getLegacyOffsetLeft`):
179
+
180
+ ```js
181
+ import { getLegacyOffsetParent } from '@brightspace-ui/core/helpers/offsetParent-legacy.js';
182
+
183
+ // Replace `element.offsetParent` with:
184
+ const offsetParent = getLegacyOffsetParent(element);
185
+ ```
186
+
174
187
  ## queueMicrotask
175
188
 
176
189
  A polyfill for [queueMicrotask](https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/queueMicrotask). For more information on microtasks, read [this article from Mozilla](https://developer.mozilla.org/en-US/docs/Web/API/HTML_DOM_API/Microtask_guide).
@@ -0,0 +1,130 @@
1
+ /**
2
+ * Adapted from:
3
+ * https://github.com/josepharhar/offsetparent-polyfills
4
+ *
5
+ * More discussion:
6
+ * https://bugs.chromium.org/p/chromium/issues/detail?id=1331803
7
+ * https://github.com/mjfroman/moz-libwebrtc-third-party/commit/047e8804fc9d871825c1005413610e934f0116d9
8
+ * https://github.com/WICG/webcomponents/issues/497
9
+ */
10
+
11
+ const originalOffsetParent = Object.getOwnPropertyDescriptor(HTMLElement.prototype, 'offsetParent').get;
12
+ const originalOffsetTop = Object.getOwnPropertyDescriptor(HTMLElement.prototype, 'offsetTop').get;
13
+ const originalOffsetLeft = Object.getOwnPropertyDescriptor(HTMLElement.prototype, 'offsetLeft').get;
14
+
15
+ function flatTreeParent(element) {
16
+ if (element.assignedSlot) {
17
+ return element.assignedSlot;
18
+ }
19
+ if (element.parentNode instanceof ShadowRoot) {
20
+ return element.parentNode.host;
21
+ }
22
+ return element.parentNode;
23
+ }
24
+
25
+ function ancestorTreeScopes(element) {
26
+ const scopes = new Set();
27
+ let currentScope = element.getRootNode();
28
+ while (currentScope) {
29
+ scopes.add(currentScope);
30
+ currentScope = currentScope.parentNode
31
+ ? currentScope.parentNode.getRootNode()
32
+ : null;
33
+ }
34
+ return scopes;
35
+ }
36
+
37
+ function offsetParentPolyfill(element, isNewBehavior) {
38
+ // Do an initial walk to check for display:none ancestors.
39
+ for (let ancestor = element; ancestor; ancestor = flatTreeParent(ancestor)) {
40
+ if (!(ancestor instanceof Element))
41
+ continue;
42
+ if (getComputedStyle(ancestor).display === 'none')
43
+ return null;
44
+ }
45
+
46
+ let scopes = null;
47
+ if (isNewBehavior)
48
+ scopes = ancestorTreeScopes(element);
49
+
50
+ for (let ancestor = flatTreeParent(element); ancestor; ancestor = flatTreeParent(ancestor)) {
51
+ if (!(ancestor instanceof Element))
52
+ continue;
53
+ const style = getComputedStyle(ancestor);
54
+ // display:contents nodes aren't in the layout tree so they should be skipped.
55
+ if (style.display === 'contents')
56
+ continue;
57
+ if (style.position !== 'static') {
58
+ if (isNewBehavior) {
59
+ if (scopes.has(ancestor.getRootNode())) {
60
+ return ancestor;
61
+ }
62
+ } else {
63
+ return ancestor;
64
+ }
65
+ }
66
+ if (ancestor.tagName === 'BODY')
67
+ return ancestor;
68
+ }
69
+ return null;
70
+ }
71
+
72
+ let isOffsetParentPatchedCached = null;
73
+ function isOffsetParentPatched() {
74
+ if (isOffsetParentPatchedCached !== null) {
75
+ return isOffsetParentPatchedCached;
76
+ }
77
+
78
+ const container = document.createElement('div');
79
+ container.style.position = 'absolute';
80
+ const shadowroot = container.attachShadow({ mode: 'open' });
81
+ document.body.appendChild(container);
82
+
83
+ const lightChild = document.createElement('div');
84
+ container.appendChild(lightChild);
85
+
86
+ const shadowChild = document.createElement('div');
87
+ shadowChild.style.position = 'absolute';
88
+ shadowChild.appendChild(document.createElement('slot'));
89
+ shadowroot.appendChild(shadowChild);
90
+
91
+ const originalValue = originalOffsetParent.apply(lightChild);
92
+ if (originalValue === container) {
93
+ isOffsetParentPatchedCached = true;
94
+ } else if (originalValue === shadowChild) {
95
+ isOffsetParentPatchedCached = false;
96
+ } else {
97
+ console.error('what ', originalValue);
98
+ }
99
+
100
+ container.remove();
101
+ return isOffsetParentPatchedCached;
102
+ }
103
+
104
+ function offsetTopLeftPolyfill(element, originalFn) {
105
+ if (!isOffsetParentPatched())
106
+ return originalFn.apply(element);
107
+
108
+ let value = originalFn.apply(element);
109
+ let nextOffsetParent = offsetParentPolyfill(element, /*isNewBehavior=*/false);
110
+ const scopes = ancestorTreeScopes(element);
111
+
112
+ while (!scopes.has(nextOffsetParent.getRootNode())) {
113
+ value -= originalFn.apply(nextOffsetParent);
114
+ nextOffsetParent = offsetParentPolyfill(nextOffsetParent, /*isNewBehavior=*/false);
115
+ }
116
+
117
+ return value;
118
+ }
119
+
120
+ export function getLegacyOffsetParent(element) {
121
+ return offsetParentPolyfill(element, /*isNewBehavior=*/false);
122
+ }
123
+
124
+ export function getLegacyOffsetTop(element) {
125
+ return offsetTopLeftPolyfill(element, originalOffsetTop);
126
+ }
127
+
128
+ export function getLegacyOffsetLeft(element) {
129
+ return offsetTopLeftPolyfill(element, originalOffsetLeft);
130
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brightspace-ui/core",
3
- "version": "2.68.0",
3
+ "version": "2.68.1",
4
4
  "description": "A collection of accessible, free, open-source web components for building Brightspace applications",
5
5
  "type": "module",
6
6
  "repository": "https://github.com/BrightspaceUI/core.git",