@brightspace-ui/core 3.79.5 → 3.79.7
Sign up to get free protection for your applications and to get access to all the features.
- 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",
|