@brightspace-ui/core 3.216.1 → 3.218.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.
- package/components/backdrop/backdrop-loading.js +142 -0
- package/components/backdrop/demo/backdrop-loading.html +66 -0
- package/components/table/table-wrapper.js +15 -1
- package/custom-elements.json +52 -4
- package/package.json +1 -1
- package/templates/primary-secondary/README.md +3 -3
- package/templates/primary-secondary/primary-secondary.js +10 -2
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import '../colors/colors.js';
|
|
2
|
+
import '../loading-spinner/loading-spinner.js';
|
|
3
|
+
import { css, html, LitElement } from 'lit';
|
|
4
|
+
import { getOffsetParent } from '../../helpers/dom.js';
|
|
5
|
+
|
|
6
|
+
const BACKDROP_DELAY_MS = 800;
|
|
7
|
+
const FADE_IN_DURATION_MS = 500;
|
|
8
|
+
const FADE_OUT_DURATION_MS = 500;
|
|
9
|
+
const SPINNER_DELAY_MS = BACKDROP_DELAY_MS + FADE_IN_DURATION_MS;
|
|
10
|
+
|
|
11
|
+
const reduceMotion = matchMedia('(prefers-reduced-motion: reduce)').matches;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* A component for displaying a semi-transparent backdrop and a loading spinner over the containing element
|
|
15
|
+
*/
|
|
16
|
+
class LoadingBackdrop extends LitElement {
|
|
17
|
+
|
|
18
|
+
static get properties() {
|
|
19
|
+
return {
|
|
20
|
+
/**
|
|
21
|
+
* Used to control whether the loading backdrop is shown
|
|
22
|
+
* @type {boolean}
|
|
23
|
+
*/
|
|
24
|
+
shown: { type: Boolean },
|
|
25
|
+
_state: { type: String, reflect: true },
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
static get styles() {
|
|
30
|
+
return css`
|
|
31
|
+
:host, .backdrop, d2l-loading-spinner {
|
|
32
|
+
height: 0%;
|
|
33
|
+
position: absolute;
|
|
34
|
+
width: 0%;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.backdrop, d2l-loading-spinner {
|
|
38
|
+
opacity: 0;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
:host {
|
|
42
|
+
top: 0;
|
|
43
|
+
z-index: 999;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.backdrop {
|
|
47
|
+
background-color: var(--d2l-color-regolith);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
d2l-loading-spinner {
|
|
51
|
+
top: 100px;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
:host([_state="showing"]),
|
|
55
|
+
:host([_state="hiding"]),
|
|
56
|
+
d2l-loading-spinner[_state="showing"],
|
|
57
|
+
d2l-loading-spinner[_state="hiding"],
|
|
58
|
+
.backdrop[_state="showing"],
|
|
59
|
+
.backdrop[_state="hiding"] {
|
|
60
|
+
height: 100%;
|
|
61
|
+
width: 100%;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
d2l-loading-spinner[_state="showing"] {
|
|
65
|
+
opacity: 1;
|
|
66
|
+
transition: opacity ${FADE_IN_DURATION_MS}ms ease-in ${SPINNER_DELAY_MS}ms;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.backdrop[_state="showing"] {
|
|
70
|
+
opacity: 0.7;
|
|
71
|
+
transition: opacity ${FADE_IN_DURATION_MS}ms ease-in ${BACKDROP_DELAY_MS}ms;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
d2l-loading-spinner[_state="hiding"],
|
|
75
|
+
.backdrop[_state="hiding"] {
|
|
76
|
+
transition: opacity ${FADE_OUT_DURATION_MS}ms ease-out;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
@media (prefers-reduced-motion: reduce) {
|
|
80
|
+
* { transition: none; }
|
|
81
|
+
}
|
|
82
|
+
`;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
constructor() {
|
|
86
|
+
super();
|
|
87
|
+
this.shown = false;
|
|
88
|
+
this._state = null;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
render() {
|
|
92
|
+
return html`
|
|
93
|
+
<div class="backdrop" _state=${this._state} @transitionend=${this.#handleTransitionEnd} @transitioncancel=${this.#hide}></div>
|
|
94
|
+
<d2l-loading-spinner _state=${this._state}></d2l-loading-spinner>
|
|
95
|
+
`;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
willUpdate(changedProperties) {
|
|
99
|
+
if (changedProperties.has('shown')) {
|
|
100
|
+
if (this.shown) {
|
|
101
|
+
this.#show();
|
|
102
|
+
} else if (changedProperties.get('shown') !== undefined) {
|
|
103
|
+
this.#fade();
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
#fade() {
|
|
109
|
+
if (reduceMotion) {
|
|
110
|
+
this.#hide();
|
|
111
|
+
} else {
|
|
112
|
+
this._state = 'hiding';
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
#handleTransitionEnd() {
|
|
117
|
+
if (this._state === 'hiding') {
|
|
118
|
+
this.#hide();
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
#hide() {
|
|
123
|
+
this._state = null;
|
|
124
|
+
|
|
125
|
+
const containingBlock = getOffsetParent(this);
|
|
126
|
+
|
|
127
|
+
if (containingBlock.dataset.initiallyInert !== '1') containingBlock.removeAttribute('inert');
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
#show() {
|
|
131
|
+
this._state = 'showing';
|
|
132
|
+
|
|
133
|
+
const containingBlock = getOffsetParent(this);
|
|
134
|
+
|
|
135
|
+
if (containingBlock.getAttribute('inert') !== null) containingBlock.dataset.initiallyInert = '1';
|
|
136
|
+
|
|
137
|
+
containingBlock.setAttribute('inert', 'inert');
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
customElements.define('d2l-backdrop-loading', LoadingBackdrop);
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
5
|
+
<meta charset="UTF-8">
|
|
6
|
+
<link rel="stylesheet" href="../../demo/styles.css" type="text/css">
|
|
7
|
+
<script type="module">
|
|
8
|
+
import '../../demo/demo-page.js';
|
|
9
|
+
import '../../button/button.js';
|
|
10
|
+
import '../backdrop-loading.js';
|
|
11
|
+
</script>
|
|
12
|
+
<style>
|
|
13
|
+
th, td {
|
|
14
|
+
border-bottom: 1px solid #dddddd;
|
|
15
|
+
padding: 30px;
|
|
16
|
+
text-align: left;
|
|
17
|
+
}
|
|
18
|
+
#grade-container {
|
|
19
|
+
position: relative;
|
|
20
|
+
width: fit-content;
|
|
21
|
+
}
|
|
22
|
+
</style>
|
|
23
|
+
</head>
|
|
24
|
+
<body unresolved>
|
|
25
|
+
<d2l-demo-page page-title="d2l-backdrop">
|
|
26
|
+
<d2l-demo-snippet>
|
|
27
|
+
<template>
|
|
28
|
+
<div id="target"><d2l-button primary>Refresh Content</d2l-button></div>
|
|
29
|
+
<div id="grade-container">
|
|
30
|
+
<table>
|
|
31
|
+
<thead>
|
|
32
|
+
<th>Course</th>
|
|
33
|
+
<th>Grade</th>
|
|
34
|
+
<th>Hours Spent in Content</th>
|
|
35
|
+
</thead>
|
|
36
|
+
<tr>
|
|
37
|
+
<td>Math</td>
|
|
38
|
+
<td class="grade">85%</td>
|
|
39
|
+
<td>100</td>
|
|
40
|
+
</tr>
|
|
41
|
+
<tr>
|
|
42
|
+
<td>Art</td>
|
|
43
|
+
<td class="grade">98%</td>
|
|
44
|
+
<td>10</td>
|
|
45
|
+
</tr>
|
|
46
|
+
</table>
|
|
47
|
+
<d2l-backdrop-loading></d2l-backdrop-loading>
|
|
48
|
+
</div>
|
|
49
|
+
<script data-demo-hide>
|
|
50
|
+
const demo = document.currentScript.parentNode;
|
|
51
|
+
const loadingBackdrop = demo.querySelector('d2l-backdrop-loading');
|
|
52
|
+
demo.querySelector('#target > d2l-button').addEventListener('click', () => {
|
|
53
|
+
loadingBackdrop.shown = !loadingBackdrop.shown;
|
|
54
|
+
setTimeout(() => {
|
|
55
|
+
demo.querySelectorAll('.grade').forEach((grade) => {
|
|
56
|
+
grade.innerHTML = `${Math.round(Math.random() * 100).toString()}%`;
|
|
57
|
+
});
|
|
58
|
+
loadingBackdrop.shown = !loadingBackdrop.shown;
|
|
59
|
+
}, 5000);
|
|
60
|
+
});
|
|
61
|
+
</script>
|
|
62
|
+
</template>
|
|
63
|
+
</d2l-demo-snippet>
|
|
64
|
+
</d2l-demo-page>
|
|
65
|
+
</body>
|
|
66
|
+
</html>
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import '../colors/colors.js';
|
|
2
2
|
import '../scroll-wrapper/scroll-wrapper.js';
|
|
3
|
+
import '../backdrop/backdrop-loading.js';
|
|
3
4
|
import { css, html, LitElement, nothing } from 'lit';
|
|
4
5
|
import { cssSizes } from '../inputs/input-checkbox.js';
|
|
5
6
|
import { getComposedParent } from '../../helpers/dom.js';
|
|
@@ -259,6 +260,7 @@ export const tableStyles = css`
|
|
|
259
260
|
[data-popover-count] {
|
|
260
261
|
z-index: 6 !important; /* if opened above, we want to stack on top of sticky table-controls */
|
|
261
262
|
}
|
|
263
|
+
|
|
262
264
|
`;
|
|
263
265
|
|
|
264
266
|
const SELECTORS = {
|
|
@@ -318,6 +320,14 @@ export class TableWrapper extends PageableMixin(SelectionMixin(LitElement)) {
|
|
|
318
320
|
reflect: true,
|
|
319
321
|
type: Boolean,
|
|
320
322
|
},
|
|
323
|
+
/**
|
|
324
|
+
* Whether or not to display a loading backdrop. Set this property when the content in the table is being refreshed.
|
|
325
|
+
* @type {boolean}
|
|
326
|
+
*/
|
|
327
|
+
loading: {
|
|
328
|
+
reflect: true,
|
|
329
|
+
type: Boolean
|
|
330
|
+
},
|
|
321
331
|
};
|
|
322
332
|
}
|
|
323
333
|
|
|
@@ -387,6 +397,7 @@ export class TableWrapper extends PageableMixin(SelectionMixin(LitElement)) {
|
|
|
387
397
|
this._tableIntersectionObserver = null;
|
|
388
398
|
this._tableMutationObserver = null;
|
|
389
399
|
this._tableScrollers = {};
|
|
400
|
+
this.loading = false;
|
|
390
401
|
}
|
|
391
402
|
|
|
392
403
|
connectedCallback() {
|
|
@@ -415,7 +426,10 @@ export class TableWrapper extends PageableMixin(SelectionMixin(LitElement)) {
|
|
|
415
426
|
}
|
|
416
427
|
|
|
417
428
|
render() {
|
|
418
|
-
const slot = html
|
|
429
|
+
const slot = html`
|
|
430
|
+
<slot @slotchange="${this._handleSlotChange}"></slot>
|
|
431
|
+
<d2l-backdrop-loading ?shown=${this.loading}></d2l-backdrop-loading>
|
|
432
|
+
`;
|
|
419
433
|
const useScrollWrapper = this.stickyHeadersScrollWrapper || !this.stickyHeaders;
|
|
420
434
|
return html`
|
|
421
435
|
<slot name="controls" @slotchange="${this._handleControlsSlotChange}"></slot>
|
package/custom-elements.json
CHANGED
|
@@ -186,6 +186,28 @@
|
|
|
186
186
|
}
|
|
187
187
|
]
|
|
188
188
|
},
|
|
189
|
+
{
|
|
190
|
+
"name": "d2l-backdrop-loading",
|
|
191
|
+
"path": "./components/backdrop/backdrop-loading.js",
|
|
192
|
+
"description": "A component for displaying a semi-transparent backdrop and a loading spinner over the containing element",
|
|
193
|
+
"attributes": [
|
|
194
|
+
{
|
|
195
|
+
"name": "shown",
|
|
196
|
+
"description": "Used to control whether the loading backdrop is shown",
|
|
197
|
+
"type": "boolean",
|
|
198
|
+
"default": "false"
|
|
199
|
+
}
|
|
200
|
+
],
|
|
201
|
+
"properties": [
|
|
202
|
+
{
|
|
203
|
+
"name": "shown",
|
|
204
|
+
"attribute": "shown",
|
|
205
|
+
"description": "Used to control whether the loading backdrop is shown",
|
|
206
|
+
"type": "boolean",
|
|
207
|
+
"default": "false"
|
|
208
|
+
}
|
|
209
|
+
]
|
|
210
|
+
},
|
|
189
211
|
{
|
|
190
212
|
"name": "d2l-backdrop",
|
|
191
213
|
"path": "./components/backdrop/backdrop.js",
|
|
@@ -14113,6 +14135,12 @@
|
|
|
14113
14135
|
"type": "'default'|'light'",
|
|
14114
14136
|
"default": "\"default\""
|
|
14115
14137
|
},
|
|
14138
|
+
{
|
|
14139
|
+
"name": "loading",
|
|
14140
|
+
"description": "Whether or not to display a loading backdrop. Set this property when the content in the table is being refreshed.",
|
|
14141
|
+
"type": "boolean",
|
|
14142
|
+
"default": "false"
|
|
14143
|
+
},
|
|
14116
14144
|
{
|
|
14117
14145
|
"name": "item-count",
|
|
14118
14146
|
"description": "Total number of items. If not specified, features like select-all-pages will be disabled.",
|
|
@@ -14189,6 +14217,13 @@
|
|
|
14189
14217
|
"type": "'default'|'light'",
|
|
14190
14218
|
"default": "\"default\""
|
|
14191
14219
|
},
|
|
14220
|
+
{
|
|
14221
|
+
"name": "loading",
|
|
14222
|
+
"attribute": "loading",
|
|
14223
|
+
"description": "Whether or not to display a loading backdrop. Set this property when the content in the table is being refreshed.",
|
|
14224
|
+
"type": "boolean",
|
|
14225
|
+
"default": "false"
|
|
14226
|
+
},
|
|
14192
14227
|
{
|
|
14193
14228
|
"name": "itemCount",
|
|
14194
14229
|
"attribute": "item-count",
|
|
@@ -14524,6 +14559,12 @@
|
|
|
14524
14559
|
"type": "'default'|'light'",
|
|
14525
14560
|
"default": "\"default\""
|
|
14526
14561
|
},
|
|
14562
|
+
{
|
|
14563
|
+
"name": "loading",
|
|
14564
|
+
"description": "Whether or not to display a loading backdrop. Set this property when the content in the table is being refreshed.",
|
|
14565
|
+
"type": "boolean",
|
|
14566
|
+
"default": "false"
|
|
14567
|
+
},
|
|
14527
14568
|
{
|
|
14528
14569
|
"name": "item-count",
|
|
14529
14570
|
"description": "Total number of items. If not specified, features like select-all-pages will be disabled.",
|
|
@@ -14565,6 +14606,13 @@
|
|
|
14565
14606
|
"type": "'default'|'light'",
|
|
14566
14607
|
"default": "\"default\""
|
|
14567
14608
|
},
|
|
14609
|
+
{
|
|
14610
|
+
"name": "loading",
|
|
14611
|
+
"attribute": "loading",
|
|
14612
|
+
"description": "Whether or not to display a loading backdrop. Set this property when the content in the table is being refreshed.",
|
|
14613
|
+
"type": "boolean",
|
|
14614
|
+
"default": "false"
|
|
14615
|
+
},
|
|
14568
14616
|
{
|
|
14569
14617
|
"name": "itemCount",
|
|
14570
14618
|
"attribute": "item-count",
|
|
@@ -15603,12 +15651,12 @@
|
|
|
15603
15651
|
],
|
|
15604
15652
|
"events": [
|
|
15605
15653
|
{
|
|
15606
|
-
"name": "d2l-
|
|
15607
|
-
"description": "Dispatched when a user begins moving the divider."
|
|
15654
|
+
"name": "d2l-iframe-pointer-events-disable",
|
|
15655
|
+
"description": "Dispatched when a user begins moving the divider to instruct iframe owners to disable pointer events."
|
|
15608
15656
|
},
|
|
15609
15657
|
{
|
|
15610
|
-
"name": "d2l-
|
|
15611
|
-
"description": "Dispatched when a user finishes moving the divider."
|
|
15658
|
+
"name": "d2l-iframe-pointer-events-enable",
|
|
15659
|
+
"description": "Dispatched when a user finishes moving the divider to instruct iframe owners to re-enable pointer events."
|
|
15612
15660
|
},
|
|
15613
15661
|
{
|
|
15614
15662
|
"name": "d2l-template-primary-secondary-form-invalid",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@brightspace-ui/core",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.218.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",
|
|
@@ -47,7 +47,7 @@ Note: this template automatically includes `<header>`, `<main>`, `<aside>` and `
|
|
|
47
47
|
|
|
48
48
|
### IFrames
|
|
49
49
|
|
|
50
|
-
If either of the panels contain an `iframe`, resizing may not work properly. This occurs because `iframe`s prevent the page template from receiving mouse events. To handle situations like these, setting `pointer-events: none` for the `iframe` is recommended during resizing. This can be done by listening for `d2l-
|
|
50
|
+
If either of the panels contain an `iframe`, resizing may not work properly. This occurs because `iframe`s prevent the page template from receiving mouse events. To handle situations like these, setting `pointer-events: none` for the `iframe` is recommended during resizing. This can be done by listening for `d2l-iframe-pointer-events-disable` and `d2l-iframe-pointer-events-enable` events.
|
|
51
51
|
|
|
52
52
|
<!-- docs: start hidden content -->
|
|
53
53
|
### Properties
|
|
@@ -63,8 +63,8 @@ If either of the panels contain an `iframe`, resizing may not work properly. Thi
|
|
|
63
63
|
| `width-type` | String, default: `'fullscreen'` | Whether content fills the screen or not. When set to `normal`, the width of the template is constrained to `1230px`. Can be one of `'fullscreen'`, `'normal'`. |
|
|
64
64
|
|
|
65
65
|
### Events
|
|
66
|
-
* `d2l-
|
|
67
|
-
* `d2l-
|
|
66
|
+
* `d2l-iframe-pointer-events-disable`: dispatched when a user begins moving the divider to instruct iframe owners to disable pointer events
|
|
67
|
+
* `d2l-iframe-pointer-events-enable`: dispatched when a user finishes moving the divider to instruct iframe owners to re-enable pointer events.
|
|
68
68
|
|
|
69
69
|
### Slots
|
|
70
70
|
* `header`: page header content
|
|
@@ -547,8 +547,8 @@ class MobileTouchResizer extends Resizer {
|
|
|
547
547
|
* @slot footer - Page footer content
|
|
548
548
|
* @slot primary - Main page content
|
|
549
549
|
* @slot secondary - Supplementary page content
|
|
550
|
-
* @fires d2l-
|
|
551
|
-
* @fires d2l-
|
|
550
|
+
* @fires d2l-iframe-pointer-events-disable - Dispatched when a user begins moving the divider to instruct iframe owners to disable pointer events.
|
|
551
|
+
* @fires d2l-iframe-pointer-events-enable - Dispatched when a user finishes moving the divider to instruct iframe owners to re-enable pointer events.
|
|
552
552
|
* @fires d2l-template-primary-secondary-form-invalid Dispatched when the form fails validation. The error map can be obtained from the detail's errors property.
|
|
553
553
|
* @fires d2l-template-primary-secondary-form-dirty Dispatched whenever any form element fires an input or change event. Can be used to track whether the form is dirty or not.
|
|
554
554
|
* @fires d2l-template-primary-secondary-form-submit Dispatched when the form is submitted. The form data can be obtained from the detail's formData property.
|
|
@@ -1262,10 +1262,18 @@ class TemplatePrimarySecondary extends LocalizeCoreElement(LitElement) {
|
|
|
1262
1262
|
}
|
|
1263
1263
|
|
|
1264
1264
|
_onPanelResizeEnd() {
|
|
1265
|
+
this.dispatchEvent(new CustomEvent('d2l-iframe-pointer-events-enable', { bubbles: true, composed: true }));
|
|
1266
|
+
/**
|
|
1267
|
+
* @ignore
|
|
1268
|
+
*/
|
|
1265
1269
|
this.dispatchEvent(new CustomEvent('d2l-template-primary-secondary-resize-end', { bubbles: true, composed: true }));
|
|
1266
1270
|
}
|
|
1267
1271
|
|
|
1268
1272
|
_onPanelResizeStart() {
|
|
1273
|
+
this.dispatchEvent(new CustomEvent('d2l-iframe-pointer-events-disable', { bubbles: true, composed: true }));
|
|
1274
|
+
/**
|
|
1275
|
+
* @ignore
|
|
1276
|
+
*/
|
|
1269
1277
|
this.dispatchEvent(new CustomEvent('d2l-template-primary-secondary-resize-start', { bubbles: true, composed: true }));
|
|
1270
1278
|
}
|
|
1271
1279
|
|