@brightspace-ui/core 3.79.5 → 3.79.7
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/components/dialog/demo/dialog-async-content.js +13 -4
- package/components/dialog/dialog-mixin.js +13 -1
- package/components/popover/popover-mixin.js +60 -12
- package/custom-elements.json +8 -0
- package/helpers/README.md +2 -1
- package/helpers/dom.js +4 -2
- package/helpers/internal/waitForElem.js +25 -0
- package/mixins/localize/README.md +1 -0
- package/package.json +1 -1
@@ -3,8 +3,9 @@ import '../../list/list-item.js';
|
|
3
3
|
import '../../list/list-item-content.js';
|
4
4
|
import { html, LitElement } from 'lit';
|
5
5
|
import { InitialStateError, runAsync } from '../../../directives/run-async/run-async.js';
|
6
|
+
import { LoadingCompleteMixin } from '../../../mixins/loading-complete/loading-complete-mixin.js';
|
6
7
|
|
7
|
-
class DialogAsyncContent extends LitElement {
|
8
|
+
class DialogAsyncContent extends LoadingCompleteMixin(LitElement) {
|
8
9
|
|
9
10
|
static get properties() {
|
10
11
|
return {
|
@@ -32,21 +33,21 @@ class DialogAsyncContent extends LitElement {
|
|
32
33
|
resolve(html`
|
33
34
|
<d2l-list>
|
34
35
|
<d2l-list-item>
|
35
|
-
<img slot="illustration" src="https://s.brightspace.com/course-images/images/38e839b1-37fa-470c-8830-b189ce4ae134/tile-high-density-max-size.jpg"
|
36
|
+
<img slot="illustration" src="https://s.brightspace.com/course-images/images/38e839b1-37fa-470c-8830-b189ce4ae134/tile-high-density-max-size.jpg" @load="${this.#handleImageLoad}">
|
36
37
|
<d2l-list-item-content>
|
37
38
|
<div>Introductory Earth Sciences</div>
|
38
39
|
<div slot="supporting-info">This course explores the geological process of the Earth's interior and surface. These include volcanism, earthquakes, mountains...</div>
|
39
40
|
</d2l-list-item-content>
|
40
41
|
</d2l-list-item>
|
41
42
|
<d2l-list-item>
|
42
|
-
<img slot="illustration" src="https://s.brightspace.com/course-images/images/e5fd575a-bc14-4a80-89e1-46f349a76178/tile-high-density-max-size.jpg"
|
43
|
+
<img slot="illustration" src="https://s.brightspace.com/course-images/images/e5fd575a-bc14-4a80-89e1-46f349a76178/tile-high-density-max-size.jpg" @load="${this.#handleImageLoad}">
|
43
44
|
<d2l-list-item-content>
|
44
45
|
<div>Engineering Materials for Energy Systems</div>
|
45
46
|
<div slot="supporting-info">This course explores the geological processes of the Earth's interior and surface. These include volcanism, earthquakes, mountain...</div>
|
46
47
|
</d2l-list-item-content>
|
47
48
|
</d2l-list-item>
|
48
49
|
<d2l-list-item>
|
49
|
-
<img slot="illustration" src="https://s.brightspace.com/course-images/images/63b162ab-b582-4bf9-8c1d-1dad04714121/tile-high-density-max-size.jpg"
|
50
|
+
<img slot="illustration" src="https://s.brightspace.com/course-images/images/63b162ab-b582-4bf9-8c1d-1dad04714121/tile-high-density-max-size.jpg" @load="${this.#handleImageLoad}">
|
50
51
|
<d2l-list-item-content>
|
51
52
|
<div>Geomorphology and GIS </div>
|
52
53
|
<div slot="supporting-info">This course explores the geological processes of the Earth's interior and surface. These include volcanism, earthquakes, mountain...</div>
|
@@ -58,6 +59,14 @@ class DialogAsyncContent extends LitElement {
|
|
58
59
|
});
|
59
60
|
}
|
60
61
|
|
62
|
+
#handleImageLoad() {
|
63
|
+
const images = this.shadowRoot.querySelectorAll('img');
|
64
|
+
for (const image of images) {
|
65
|
+
if (!image.complete) return;
|
66
|
+
}
|
67
|
+
this.resolveLoadingComplete();
|
68
|
+
}
|
69
|
+
|
61
70
|
}
|
62
71
|
|
63
72
|
customElements.define('d2l-dialog-demo-async-content', DialogAsyncContent);
|
@@ -2,7 +2,7 @@ import '../focus-trap/focus-trap.js';
|
|
2
2
|
import '../../helpers/viewport-size.js';
|
3
3
|
import { allowBodyScroll, preventBodyScroll } from '../backdrop/backdrop.js';
|
4
4
|
import { clearDismissible, setDismissible } from '../../helpers/dismissible.js';
|
5
|
-
import { findComposedAncestor, isComposedAncestor } from '../../helpers/dom.js';
|
5
|
+
import { findComposedAncestor, getComposedChildren, isComposedAncestor } from '../../helpers/dom.js';
|
6
6
|
import { getComposedActiveElement, getFirstFocusableDescendant, getNextFocusable, isFocusable } from '../../helpers/focus.js';
|
7
7
|
import { classMap } from 'lit/directives/class-map.js';
|
8
8
|
import { getUniqueId } from '../../helpers/uniqueId.js';
|
@@ -11,6 +11,7 @@ import { ifDefined } from 'lit/directives/if-defined.js';
|
|
11
11
|
import { RtlMixin } from '../../mixins/rtl/rtl-mixin.js';
|
12
12
|
import { styleMap } from 'lit/directives/style-map.js';
|
13
13
|
import { tryGetIfrauBackdropService } from '../../helpers/ifrauBackdropService.js';
|
14
|
+
import { waitForElem } from '../../helpers/internal/waitForElem.js';
|
14
15
|
|
15
16
|
window.D2L = window.D2L || {};
|
16
17
|
window.D2L.DialogMixin = window.D2L.DialogMixin || {};
|
@@ -452,6 +453,11 @@ export const DialogMixin = superclass => class extends RtlMixin(superclass) {
|
|
452
453
|
if (reduceMotion) await new Promise(resolve => requestAnimationFrame(resolve));
|
453
454
|
else await animPromise;
|
454
455
|
|
456
|
+
const flag = window.D2L?.LP?.Web?.UI?.Flags.Flag('GAUD-7397-dialog-resize-updateComplete', true) ?? true;
|
457
|
+
if (flag) {
|
458
|
+
await this.#waitForUpdateComplete();
|
459
|
+
}
|
460
|
+
await this._updateSize();
|
455
461
|
/** Dispatched when the dialog is opened */
|
456
462
|
this.dispatchEvent(new CustomEvent(
|
457
463
|
'd2l-dialog-open', { bubbles: true, composed: true }
|
@@ -580,4 +586,10 @@ export const DialogMixin = superclass => class extends RtlMixin(superclass) {
|
|
580
586
|
});
|
581
587
|
});
|
582
588
|
}
|
589
|
+
|
590
|
+
async #waitForUpdateComplete() {
|
591
|
+
const predicate = () => true;
|
592
|
+
const composedChildren = getComposedChildren(this, predicate);
|
593
|
+
await Promise.all(composedChildren.map(child => waitForElem(child, predicate)));
|
594
|
+
}
|
583
595
|
};
|
@@ -1,3 +1,4 @@
|
|
1
|
+
import '../backdrop/backdrop.js';
|
1
2
|
import '../colors/colors.js';
|
2
3
|
import '../focus-trap/focus-trap.js';
|
3
4
|
import { clearDismissible, setDismissible } from '../../helpers/dismissible.js';
|
@@ -6,6 +7,7 @@ import { getComposedActiveElement, getFirstFocusableDescendant, getPreviousFocus
|
|
6
7
|
import { getComposedParent, isComposedAncestor } from '../../helpers/dom.js';
|
7
8
|
import { _offscreenStyleDeclarations } from '../offscreen/offscreen.js';
|
8
9
|
import { styleMap } from 'lit/directives/style-map.js';
|
10
|
+
import { tryGetIfrauBackdropService } from '../../helpers/ifrauBackdropService.js';
|
9
11
|
|
10
12
|
const defaultPreferredPosition = {
|
11
13
|
location: 'block-end', // block-start, block-end
|
@@ -46,6 +48,7 @@ export const PopoverMixin = superclass => class extends superclass {
|
|
46
48
|
_position: { state: true },
|
47
49
|
_preferredPosition: { state: true },
|
48
50
|
_rtl: { state: true },
|
51
|
+
_showBackdrop: { state: true },
|
49
52
|
_trapFocus: { state: true },
|
50
53
|
_useNativePopover: { type: String, reflect: true, attribute: 'popover' },
|
51
54
|
_width: { state: true }
|
@@ -207,6 +210,7 @@ export const PopoverMixin = superclass => class extends superclass {
|
|
207
210
|
super();
|
208
211
|
this.configure();
|
209
212
|
this._mobile = false;
|
213
|
+
this._showBackdrop = false;
|
210
214
|
this._useNativePopover = isSupported ? 'manual' : undefined;
|
211
215
|
this.#handleAncestorMutationBound = this.#handleAncestorMutation.bind(this);
|
212
216
|
this.#handleAutoCloseClickBound = this.#handleAutoCloseClick.bind(this);
|
@@ -236,8 +240,9 @@ export const PopoverMixin = superclass => class extends superclass {
|
|
236
240
|
async close() {
|
237
241
|
if (!this._opened) return;
|
238
242
|
|
239
|
-
|
243
|
+
const ifrauBackdropService = await tryGetIfrauBackdropService();
|
240
244
|
|
245
|
+
this._opened = false;
|
241
246
|
if (this._useNativePopover) this.hidePopover();
|
242
247
|
|
243
248
|
this._previousFocusableAncestor = null;
|
@@ -245,6 +250,13 @@ export const PopoverMixin = superclass => class extends superclass {
|
|
245
250
|
this.#removeMediaQueryHandlers();
|
246
251
|
this.#removeRepositionHandlers();
|
247
252
|
this.#clearDismissible();
|
253
|
+
|
254
|
+
if (ifrauBackdropService && this._showBackdrop) {
|
255
|
+
ifrauBackdropService.hideBackdrop();
|
256
|
+
this.#ifrauContextInfo = null;
|
257
|
+
}
|
258
|
+
this._showBackdrop = false;
|
259
|
+
|
248
260
|
await this.updateComplete; // wait before applying focus to opener
|
249
261
|
this.#focusOpener();
|
250
262
|
this.dispatchEvent(new CustomEvent('d2l-popover-close', { bubbles: true, composed: true }));
|
@@ -281,6 +293,8 @@ export const PopoverMixin = superclass => class extends superclass {
|
|
281
293
|
async open(applyFocus = true) {
|
282
294
|
if (this._opened) return;
|
283
295
|
|
296
|
+
const ifrauBackdropService = await tryGetIfrauBackdropService();
|
297
|
+
|
284
298
|
this.#addMediaQueryHandlers();
|
285
299
|
|
286
300
|
this._rtl = document.documentElement.getAttribute('dir') === 'rtl';
|
@@ -297,6 +311,11 @@ export const PopoverMixin = superclass => class extends superclass {
|
|
297
311
|
|
298
312
|
await this.#position();
|
299
313
|
|
314
|
+
this._showBackdrop = this._mobile && this._mobileTrayLocation;
|
315
|
+
if (ifrauBackdropService && this._showBackdrop) {
|
316
|
+
this.#ifrauContextInfo = await ifrauBackdropService.showBackdrop();
|
317
|
+
}
|
318
|
+
|
300
319
|
this._dismissibleId = setDismissible(() => this.close());
|
301
320
|
|
302
321
|
this.#focusContent(this);
|
@@ -323,7 +342,7 @@ export const PopoverMixin = superclass => class extends superclass {
|
|
323
342
|
const contentStyle = stylesMap['content'];
|
324
343
|
|
325
344
|
content = html`
|
326
|
-
<div class="content-width vdiff-target" style=${styleMap(widthStyle)}>
|
345
|
+
<div id="content-wrapper" class="content-width vdiff-target" style=${styleMap(widthStyle)}>
|
327
346
|
<div class="content-container" style=${styleMap(contentStyle)}>${content}</div>
|
328
347
|
</div>
|
329
348
|
`;
|
@@ -362,12 +381,16 @@ export const PopoverMixin = superclass => class extends superclass {
|
|
362
381
|
</div>
|
363
382
|
` : nothing;
|
364
383
|
|
365
|
-
|
384
|
+
const backdrop = this._mobileTrayLocation ?
|
385
|
+
html`<d2l-backdrop for-target="content-wrapper" ?shown="${this._showBackdrop}"></d2l-backdrop>` :
|
386
|
+
nothing;
|
387
|
+
return html`${content}${backdrop}${pointer}`;
|
366
388
|
|
367
389
|
}
|
368
390
|
|
369
391
|
async resize() {
|
370
392
|
if (!this._opened) return;
|
393
|
+
this._showBackdrop = this._mobile && this._mobileTrayLocation;
|
371
394
|
await this.#position();
|
372
395
|
}
|
373
396
|
|
@@ -376,6 +399,7 @@ export const PopoverMixin = superclass => class extends superclass {
|
|
376
399
|
else return this.open(!this._noAutoFocus && applyFocus);
|
377
400
|
}
|
378
401
|
|
402
|
+
#ifrauContextInfo;
|
379
403
|
#mediaQueryList;
|
380
404
|
#handleAncestorMutationBound;
|
381
405
|
#handleAutoCloseClickBound;
|
@@ -520,7 +544,8 @@ export const PopoverMixin = superclass => class extends superclass {
|
|
520
544
|
#getMobileTrayBlockStyleMaps() {
|
521
545
|
|
522
546
|
let maxHeightOverride;
|
523
|
-
|
547
|
+
let availableHeight = Math.min(window.innerHeight, window.screen.height);
|
548
|
+
if (this.#ifrauContextInfo) availableHeight = this.#ifrauContextInfo.availableHeight;
|
524
549
|
|
525
550
|
// default maximum height for bottom tray (42px margin)
|
526
551
|
const mobileTrayMaxHeightDefault = availableHeight - minBackdropHeightMobile;
|
@@ -532,12 +557,20 @@ export const PopoverMixin = superclass => class extends superclass {
|
|
532
557
|
}
|
533
558
|
maxHeightOverride = `${maxHeightOverride}px`;
|
534
559
|
|
560
|
+
let bottomOverride;
|
561
|
+
if (this.#ifrauContextInfo) {
|
562
|
+
// the bottom override is measured as the distance from the bottom of the screen
|
563
|
+
const screenHeight = window.innerHeight - this.#ifrauContextInfo.availableHeight + Math.min(this.#ifrauContextInfo.top, 0);
|
564
|
+
bottomOverride = `${screenHeight}px`;
|
565
|
+
}
|
566
|
+
|
535
567
|
const widthOverride = '100vw';
|
536
568
|
|
537
569
|
const widthStyle = {
|
538
570
|
minWidth: widthOverride,
|
539
571
|
width: widthOverride,
|
540
572
|
maxHeight: maxHeightOverride,
|
573
|
+
bottom: bottomOverride
|
541
574
|
};
|
542
575
|
|
543
576
|
const contentWidthStyle = {
|
@@ -552,14 +585,15 @@ export const PopoverMixin = superclass => class extends superclass {
|
|
552
585
|
|
553
586
|
return {
|
554
587
|
width: widthStyle,
|
555
|
-
content: contentStyle
|
588
|
+
content: contentStyle
|
556
589
|
};
|
557
590
|
}
|
558
591
|
|
559
592
|
#getMobileTrayInlineStyleMaps() {
|
560
593
|
|
561
594
|
let maxWidthOverride = this._maxWidth;
|
562
|
-
|
595
|
+
let availableWidth = Math.min(window.innerWidth, window.screen.width);
|
596
|
+
if (this.#ifrauContextInfo) availableWidth = this.#ifrauContextInfo.availableWidth;
|
563
597
|
|
564
598
|
// default maximum width for tray (30px margin)
|
565
599
|
const mobileTrayMaxWidthDefault = Math.min(availableWidth - minBackdropWidthMobile, 420);
|
@@ -592,7 +626,16 @@ export const PopoverMixin = superclass => class extends superclass {
|
|
592
626
|
// add 2 to content width since scrollWidth does not include border
|
593
627
|
const containerWidth = `${widthOverride + 20}px`;
|
594
628
|
|
595
|
-
const
|
629
|
+
const maxHeightOverride = this.#ifrauContextInfo ? `${this.#ifrauContextInfo.availableHeight}px` : '';
|
630
|
+
|
631
|
+
let topOverride;
|
632
|
+
if (this.#ifrauContextInfo) {
|
633
|
+
// if inside iframe, use ifrauContext top as top of screen
|
634
|
+
topOverride = `${this.#ifrauContextInfo.top < 0 ? -this.#ifrauContextInfo.top : 0}px`;
|
635
|
+
} else if (window.innerHeight > window.screen.height) {
|
636
|
+
// non-responsive page, manually override top to scroll distance
|
637
|
+
topOverride = window.pageYOffset;
|
638
|
+
}
|
596
639
|
|
597
640
|
let inlineEndOverride;
|
598
641
|
let inlineStartOverride;
|
@@ -614,6 +657,7 @@ export const PopoverMixin = superclass => class extends superclass {
|
|
614
657
|
minWidth: minWidthOverride,
|
615
658
|
width: containerWidth,
|
616
659
|
top: topOverride,
|
660
|
+
maxHeight: maxHeightOverride,
|
617
661
|
insetInlineStart: inlineStartOverride,
|
618
662
|
insetInlineEnd: inlineEndOverride
|
619
663
|
};
|
@@ -626,11 +670,12 @@ export const PopoverMixin = superclass => class extends superclass {
|
|
626
670
|
|
627
671
|
const contentStyle = {
|
628
672
|
...contentWidthStyle,
|
673
|
+
maxHeight: maxHeightOverride,
|
629
674
|
};
|
630
675
|
|
631
676
|
return {
|
632
|
-
width
|
633
|
-
content
|
677
|
+
width: widthStyle,
|
678
|
+
content: contentStyle
|
634
679
|
};
|
635
680
|
}
|
636
681
|
|
@@ -767,8 +812,8 @@ export const PopoverMixin = superclass => class extends superclass {
|
|
767
812
|
};
|
768
813
|
|
769
814
|
return {
|
770
|
-
width
|
771
|
-
content
|
815
|
+
width: widthStyle,
|
816
|
+
content: contentStyle
|
772
817
|
};
|
773
818
|
}
|
774
819
|
|
@@ -824,7 +869,10 @@ export const PopoverMixin = superclass => class extends superclass {
|
|
824
869
|
|
825
870
|
async #handleMobileResize() {
|
826
871
|
this._mobile = this.#mediaQueryList.matches;
|
827
|
-
if (this._opened)
|
872
|
+
if (this._opened) {
|
873
|
+
this._showBackdrop = this._mobile && this._mobileTrayLocation;
|
874
|
+
await this.#position();
|
875
|
+
}
|
828
876
|
}
|
829
877
|
|
830
878
|
#handleResize() {
|
package/custom-elements.json
CHANGED
@@ -1996,6 +1996,14 @@
|
|
1996
1996
|
"name": "href",
|
1997
1997
|
"attribute": "href",
|
1998
1998
|
"type": "string"
|
1999
|
+
},
|
2000
|
+
{
|
2001
|
+
"name": "loadingComplete",
|
2002
|
+
"type": "Promise<any>"
|
2003
|
+
},
|
2004
|
+
{
|
2005
|
+
"name": "resolveLoadingComplete",
|
2006
|
+
"type": "() => void"
|
1999
2007
|
}
|
2000
2008
|
]
|
2001
2009
|
},
|
package/helpers/README.md
CHANGED
@@ -86,7 +86,8 @@ elemIdListRemoves(node, attrName, value);
|
|
86
86
|
findComposedAncestor(node, predicate);
|
87
87
|
|
88
88
|
// gets the composed children (including shadow children & distributed children)
|
89
|
-
|
89
|
+
// includes a predicate which will add children nodes when predicate(node) is true
|
90
|
+
getComposedChildren(element, predicate = () => true);
|
90
91
|
|
91
92
|
// gets the composed parent (including shadow host & insertion points)
|
92
93
|
getComposedParent(node);
|
package/helpers/dom.js
CHANGED
@@ -79,7 +79,7 @@ export function getBoundingAncestor(node) {
|
|
79
79
|
});
|
80
80
|
}
|
81
81
|
|
82
|
-
export function getComposedChildren(node) {
|
82
|
+
export function getComposedChildren(node, predicate = () => true) {
|
83
83
|
|
84
84
|
if (!node) {
|
85
85
|
return null;
|
@@ -104,7 +104,9 @@ export function getComposedChildren(node) {
|
|
104
104
|
|
105
105
|
for (let i = 0; i < nodes.length; i++) {
|
106
106
|
if (nodes[i].nodeType === 1) {
|
107
|
-
|
107
|
+
if (predicate(nodes[i])) {
|
108
|
+
children.push(nodes[i]);
|
109
|
+
}
|
108
110
|
}
|
109
111
|
}
|
110
112
|
|
@@ -0,0 +1,25 @@
|
|
1
|
+
import { getComposedChildren } from '../dom.js';
|
2
|
+
|
3
|
+
export async function waitForElem(elem, predicate = () => true) {
|
4
|
+
|
5
|
+
if (!elem) return;
|
6
|
+
|
7
|
+
const update = elem.updateComplete;
|
8
|
+
if (typeof update === 'object' && Promise.resolve(update) === update) {
|
9
|
+
await update;
|
10
|
+
await new Promise(resolve => {
|
11
|
+
requestAnimationFrame(() => resolve());
|
12
|
+
});
|
13
|
+
}
|
14
|
+
|
15
|
+
if (typeof elem.getLoadingComplete === 'function') {
|
16
|
+
await elem.getLoadingComplete();
|
17
|
+
await new Promise(resolve => {
|
18
|
+
requestAnimationFrame(() => resolve());
|
19
|
+
});
|
20
|
+
}
|
21
|
+
|
22
|
+
const children = getComposedChildren(elem, predicate);
|
23
|
+
await Promise.all(children.map(e => waitForElem(e, predicate)));
|
24
|
+
|
25
|
+
}
|
@@ -196,6 +196,7 @@ static get localizeConfig() {
|
|
196
196
|
};
|
197
197
|
}
|
198
198
|
```
|
199
|
+
See [Creating a new collection](https://desire2learn.atlassian.net/wiki/spaces/DEVCENTRAL/pages/3105063520/OSLO#Creating-a-new-collection) to determine your collection name. Backslash (`\`) characters in your collection name must be escaped.
|
199
200
|
|
200
201
|
> **Important:** When defining language resource keys, avoid using the Full Stop (`.`) character for grouping. OSLO does not support it.
|
201
202
|
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@brightspace-ui/core",
|
3
|
-
"version": "3.79.
|
3
|
+
"version": "3.79.7",
|
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",
|