@brightspace-ui/core 3.9.1 → 3.10.0
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.
@@ -164,6 +164,14 @@ export const DropdownContentMixin = superclass => class extends LocalizeCoreElem
|
|
164
164
|
reflect: true,
|
165
165
|
attribute: 'no-pointer'
|
166
166
|
},
|
167
|
+
/**
|
168
|
+
* Private, set by the opener depending on whether it's intersecting
|
169
|
+
* @ignore
|
170
|
+
*/
|
171
|
+
offscreen: {
|
172
|
+
type: Boolean,
|
173
|
+
reflect: true
|
174
|
+
},
|
167
175
|
/**
|
168
176
|
* Whether the dropdown is open or not
|
169
177
|
* @type {boolean}
|
@@ -285,6 +293,7 @@ export const DropdownContentMixin = superclass => class extends LocalizeCoreElem
|
|
285
293
|
this._verticalOffset = defaultVerticalOffset;
|
286
294
|
|
287
295
|
this.__reposition = this.__reposition.bind(this);
|
296
|
+
this.__onAncestorMutation = this.__onAncestorMutation.bind(this);
|
288
297
|
this.__onResize = this.__onResize.bind(this);
|
289
298
|
this.__onAutoCloseFocus = this.__onAutoCloseFocus.bind(this);
|
290
299
|
this.__onAutoCloseClick = this.__onAutoCloseClick.bind(this);
|
@@ -458,10 +467,16 @@ export const DropdownContentMixin = superclass => class extends LocalizeCoreElem
|
|
458
467
|
return (value === 'scroll' || value === 'auto');
|
459
468
|
};
|
460
469
|
|
461
|
-
let node = this;
|
462
470
|
this.__removeRepositionHandlers();
|
471
|
+
|
472
|
+
this._ancestorMutationObserver ??= new MutationObserver(this.__onAncestorMutation);
|
473
|
+
const mutationConfig = { attributes: true, childList: true, subtree: true };
|
474
|
+
|
475
|
+
let node = this;
|
463
476
|
this._scrollablesObserved = [];
|
464
477
|
while (node) {
|
478
|
+
|
479
|
+
// observe scrollables
|
465
480
|
let observeScrollable = false;
|
466
481
|
if (node.nodeType === Node.ELEMENT_NODE) {
|
467
482
|
observeScrollable = isScrollable(node, 'overflow-y') || isScrollable(node, 'overflow-x');
|
@@ -472,6 +487,12 @@ export const DropdownContentMixin = superclass => class extends LocalizeCoreElem
|
|
472
487
|
this._scrollablesObserved.push(node);
|
473
488
|
node.addEventListener('scroll', this.__reposition);
|
474
489
|
}
|
490
|
+
|
491
|
+
// observe mutations on each DOM scope (excludes sibling scopes... can only do so much)
|
492
|
+
if (node.nodeType === Node.DOCUMENT_NODE || (node.nodeType === Node.DOCUMENT_FRAGMENT_NODE && node.host)) {
|
493
|
+
this._ancestorMutationObserver.observe(node, mutationConfig);
|
494
|
+
}
|
495
|
+
|
475
496
|
node = getComposedParent(node);
|
476
497
|
}
|
477
498
|
|
@@ -528,6 +549,13 @@ export const DropdownContentMixin = superclass => class extends LocalizeCoreElem
|
|
528
549
|
this._hasHeader = e.target.assignedNodes().length !== 0;
|
529
550
|
}
|
530
551
|
|
552
|
+
__onAncestorMutation(mutations) {
|
553
|
+
const opener = this.__getOpener();
|
554
|
+
// ignore mutations that are within this dropdown
|
555
|
+
const reposition = !!mutations.find(mutation => !isComposedAncestor(opener, mutation.target));
|
556
|
+
if (reposition) this.__reposition();
|
557
|
+
}
|
558
|
+
|
531
559
|
__onAutoCloseClick(e) {
|
532
560
|
if (!this.opened || this.noAutoClose) {
|
533
561
|
return;
|
@@ -791,12 +819,13 @@ export const DropdownContentMixin = superclass => class extends LocalizeCoreElem
|
|
791
819
|
|
792
820
|
__removeRepositionHandlers() {
|
793
821
|
if (!this._fixedPositioning) return;
|
794
|
-
if (!this._scrollablesObserved) return;
|
795
822
|
|
796
|
-
this._scrollablesObserved
|
823
|
+
this._scrollablesObserved?.forEach(node => {
|
797
824
|
node.removeEventListener('scroll', this.__reposition);
|
798
825
|
});
|
799
826
|
this._scrollablesObserved = null;
|
827
|
+
|
828
|
+
this._ancestorMutationObserver?.disconnect();
|
800
829
|
}
|
801
830
|
|
802
831
|
__reposition() {
|
@@ -1,4 +1,5 @@
|
|
1
1
|
import '../colors/colors.js';
|
2
|
+
import { _offscreenStyleDeclarations } from '../offscreen/offscreen.js';
|
2
3
|
import { css } from 'lit';
|
3
4
|
|
4
5
|
const pointerLength = 16;
|
@@ -349,4 +350,7 @@ export const dropdownContentStyles = css`
|
|
349
350
|
}
|
350
351
|
}
|
351
352
|
|
353
|
+
:host([offscreen]) {
|
354
|
+
${_offscreenStyleDeclarations}
|
355
|
+
}
|
352
356
|
`;
|
@@ -1,6 +1,12 @@
|
|
1
1
|
import { getUniqueId } from '../../helpers/uniqueId.js';
|
2
2
|
import { isComposedAncestor } from '../../helpers/dom.js';
|
3
3
|
|
4
|
+
const intersectionObserver = new IntersectionObserver(entries => {
|
5
|
+
entries.forEach(entry => {
|
6
|
+
entry.target.__updateContentVisibility(entry.isIntersecting);
|
7
|
+
});
|
8
|
+
}, { threshold: 0 }); // 0-1 (0 -> intersection requires any pixel visible, 1 -> intersection requires all pixels visible)
|
9
|
+
|
4
10
|
export const DropdownOpenerMixin = superclass => class extends superclass {
|
5
11
|
|
6
12
|
static get properties() {
|
@@ -91,6 +97,9 @@ export const DropdownOpenerMixin = superclass => class extends superclass {
|
|
91
97
|
this.addEventListener('mouseenter', this.__onMouseEnter);
|
92
98
|
this.addEventListener('mouseleave', this.__onMouseLeave);
|
93
99
|
|
100
|
+
if (this._fixedPositioning && this.dropdownOpened) {
|
101
|
+
intersectionObserver.observe(this);
|
102
|
+
}
|
94
103
|
if (this.openOnHover) {
|
95
104
|
document.body.addEventListener('mouseup', this._onOutsideClick);
|
96
105
|
}
|
@@ -104,6 +113,9 @@ export const DropdownOpenerMixin = superclass => class extends superclass {
|
|
104
113
|
this.removeEventListener('mouseenter', this.__onMouseEnter);
|
105
114
|
this.removeEventListener('mouseleave', this.__onMouseLeave);
|
106
115
|
|
116
|
+
if (this._fixedPositioning) {
|
117
|
+
intersectionObserver.unobserve(this);
|
118
|
+
}
|
107
119
|
if (this.openOnHover) {
|
108
120
|
document.body.removeEventListener('mouseup', this._onOutsideClick);
|
109
121
|
}
|
@@ -137,7 +149,7 @@ export const DropdownOpenerMixin = superclass => class extends superclass {
|
|
137
149
|
}
|
138
150
|
|
139
151
|
willUpdate(changedProperties) {
|
140
|
-
if (changedProperties.has('preferFixedPositioning')) {
|
152
|
+
if (this._fixedPositioning === undefined || changedProperties.has('preferFixedPositioning')) {
|
141
153
|
this._fixedPositioning = (window.D2L?.LP?.Web?.UI?.Flags.Flag('GAUD-131-dropdown-fixed-positioning', false) && this.preferFixedPositioning);
|
142
154
|
}
|
143
155
|
}
|
@@ -207,6 +219,10 @@ export const DropdownOpenerMixin = superclass => class extends superclass {
|
|
207
219
|
}
|
208
220
|
|
209
221
|
__onClosed() {
|
222
|
+
if (this._fixedPositioning) {
|
223
|
+
intersectionObserver.unobserve(this);
|
224
|
+
}
|
225
|
+
|
210
226
|
const opener = this.getOpenerElement();
|
211
227
|
if (!opener) {
|
212
228
|
return;
|
@@ -280,6 +296,10 @@ export const DropdownOpenerMixin = superclass => class extends superclass {
|
|
280
296
|
opener.setAttribute('aria-expanded', 'true');
|
281
297
|
opener.setAttribute('active', 'true');
|
282
298
|
this._isFading = false;
|
299
|
+
|
300
|
+
if (this._fixedPositioning) {
|
301
|
+
intersectionObserver.observe(this);
|
302
|
+
}
|
283
303
|
}
|
284
304
|
|
285
305
|
__onOpenerMouseUp(e) {
|
@@ -301,6 +321,10 @@ export const DropdownOpenerMixin = superclass => class extends superclass {
|
|
301
321
|
} else this.toggleOpen(true);
|
302
322
|
}
|
303
323
|
|
324
|
+
__updateContentVisibility(visible) {
|
325
|
+
this.__getContentElement().offscreen = !visible;
|
326
|
+
}
|
327
|
+
|
304
328
|
/* used by open-on-hover option */
|
305
329
|
_closeTimerStart() {
|
306
330
|
if (this.dropdownOpened) return;
|
@@ -1,7 +1,10 @@
|
|
1
1
|
import { css, html, LitElement } from 'lit';
|
2
2
|
import { RtlMixin } from '../../mixins/rtl/rtl-mixin.js';
|
3
3
|
|
4
|
-
|
4
|
+
/**
|
5
|
+
* A private helper declarations that should not be used by general consumers
|
6
|
+
*/
|
7
|
+
export const _offscreenStyleDeclarations = css`
|
5
8
|
direction: var(--d2l-document-direction, ${document.dir === 'rtl' ? css`rtl` : css`ltr`}); /* stylelint-disable-line @stylistic/string-quotes */
|
6
9
|
height: 1px;
|
7
10
|
inset-inline-start: -10000px;
|
@@ -14,7 +17,7 @@ const offscreenStyleDeclarations = css`
|
|
14
17
|
|
15
18
|
export const offscreenStyles = css`
|
16
19
|
.d2l-offscreen {
|
17
|
-
${
|
20
|
+
${_offscreenStyleDeclarations}
|
18
21
|
}
|
19
22
|
`;
|
20
23
|
|
@@ -26,7 +29,7 @@ class Offscreen extends RtlMixin(LitElement) {
|
|
26
29
|
static get styles() {
|
27
30
|
return css`
|
28
31
|
:host {
|
29
|
-
${
|
32
|
+
${_offscreenStyleDeclarations}
|
30
33
|
}
|
31
34
|
`;
|
32
35
|
}
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@brightspace-ui/core",
|
3
|
-
"version": "3.
|
3
|
+
"version": "3.10.0",
|
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",
|