@brightspace-ui/core 3.254.2 → 3.256.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 +16 -21
- package/components/form/docs/form-element-container-mixin.md +28 -0
- package/components/form/form-element-container-mixin.js +8 -0
- package/components/form/form-helper.js +18 -8
- package/components/page/page-header-custom.js +12 -1
- package/custom-elements.json +28 -0
- package/package.json +1 -1
|
@@ -3,16 +3,11 @@ import '../loading-spinner/loading-spinner.js';
|
|
|
3
3
|
import './backdrop-dirty-overlay.js';
|
|
4
4
|
import { css, html, LitElement, nothing } from 'lit';
|
|
5
5
|
import { getComposedChildren, getComposedParent } from '../../helpers/dom.js';
|
|
6
|
-
import { classMap } from 'lit/directives/class-map.js';
|
|
7
|
-
import { getFlag } from '../../helpers/flags.js';
|
|
8
6
|
import { LocalizeCoreElement } from '../../helpers/localize-core-element.js';
|
|
9
|
-
import { offscreenStyles } from '../offscreen/offscreen.js';
|
|
10
7
|
|
|
11
8
|
import { PropertyRequiredMixin } from '../../mixins/property-required/property-required-mixin.js';
|
|
12
9
|
import { styleMap } from 'lit/directives/style-map.js';
|
|
13
10
|
|
|
14
|
-
const OffSCREEN_SIZELESS = getFlag('d2l-offscreen-sizeless', true);
|
|
15
|
-
|
|
16
11
|
const BACKDROP_DELAY_MS = 800;
|
|
17
12
|
const FADE_DURATION_MS = 500;
|
|
18
13
|
const SPINNER_DELAY_MS = FADE_DURATION_MS;
|
|
@@ -139,7 +134,7 @@ class LoadingBackdrop extends PropertyRequiredMixin(LocalizeCoreElement(LitEleme
|
|
|
139
134
|
@media (prefers-reduced-motion: reduce) {
|
|
140
135
|
* { transition: none; }
|
|
141
136
|
}
|
|
142
|
-
|
|
137
|
+
`];
|
|
143
138
|
}
|
|
144
139
|
|
|
145
140
|
constructor() {
|
|
@@ -152,18 +147,26 @@ class LoadingBackdrop extends PropertyRequiredMixin(LocalizeCoreElement(LitEleme
|
|
|
152
147
|
}
|
|
153
148
|
|
|
154
149
|
render() {
|
|
155
|
-
const
|
|
156
|
-
const dirtyStateVisible = this._state !== 'hidden' && this.dataState === 'dirty';
|
|
150
|
+
const backdropVisible = this._state !== 'hidden';
|
|
157
151
|
|
|
158
152
|
return html`
|
|
159
|
-
${
|
|
153
|
+
${backdropVisible ?
|
|
160
154
|
html`<div id="visible">
|
|
161
155
|
<div class="backdrop" @transitionend="${this.#handleTransitionEnd}" @transitioncancel="${this.#handleTransitionEnd}"></div>
|
|
162
156
|
<d2l-loading-spinner style=${styleMap({ top: `${this._spinnerTop}px` })} size="${LOADING_SPINNER_SIZE}"></d2l-loading-spinner>
|
|
163
|
-
</div>`
|
|
157
|
+
</div>` : nothing
|
|
164
158
|
}
|
|
165
|
-
<div aria-live="polite"
|
|
166
|
-
${
|
|
159
|
+
<div aria-live="polite" id="d2l-live-region">
|
|
160
|
+
${backdropVisible ?
|
|
161
|
+
html`<d2l-backdrop-dirty-overlay
|
|
162
|
+
style=${styleMap({ top: `${this._dirtyDialogTop}px` })}
|
|
163
|
+
description="${this.dirtyText}"
|
|
164
|
+
action="${this.dirtyButtonText}"
|
|
165
|
+
?inert=${this.dataState !== 'dirty'}
|
|
166
|
+
></d2l-backdrop-dirty-overlay>` : nothing }
|
|
167
|
+
<d2l-offscreen>
|
|
168
|
+
${this._ariaContent}
|
|
169
|
+
</d2l-offscreen>
|
|
167
170
|
</div>
|
|
168
171
|
`;
|
|
169
172
|
}
|
|
@@ -257,7 +260,7 @@ class LoadingBackdrop extends PropertyRequiredMixin(LocalizeCoreElement(LitEleme
|
|
|
257
260
|
#fade() {
|
|
258
261
|
let hideImmediately = reduceMotion || this._state === 'showing';
|
|
259
262
|
if (this._state === 'shown') {
|
|
260
|
-
const currentOpacity = getComputedStyle(this.shadowRoot.querySelector('
|
|
263
|
+
const currentOpacity = getComputedStyle(this.shadowRoot.querySelector('#d2l-live-region')).opacity;
|
|
261
264
|
hideImmediately ||= (currentOpacity === '0');
|
|
262
265
|
}
|
|
263
266
|
|
|
@@ -296,14 +299,6 @@ class LoadingBackdrop extends PropertyRequiredMixin(LocalizeCoreElement(LitEleme
|
|
|
296
299
|
if (containingBlock.dataset.initiallyInert !== '1') containingBlock.removeAttribute('inert');
|
|
297
300
|
}
|
|
298
301
|
|
|
299
|
-
#renderDirtyOverlay() {
|
|
300
|
-
return html`<d2l-backdrop-dirty-overlay
|
|
301
|
-
style=${styleMap({ top: `${this._dirtyDialogTop}px` })}
|
|
302
|
-
description="${this.dirtyText}"
|
|
303
|
-
action="${this.dirtyButtonText}"
|
|
304
|
-
></d2l-backdrop-dirty-overlay>`;
|
|
305
|
-
}
|
|
306
|
-
|
|
307
302
|
#setLiveArea(content, { delay } = {}) {
|
|
308
303
|
this.announcementTimeout = setTimeout(() => this._ariaContent = content, delay || 0);
|
|
309
304
|
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# FormElementContainerMixin
|
|
2
|
+
|
|
3
|
+
Extending `FormElementContainerMixin` will allow a custom element's children (native or [custom](./form-element-mixin.md)) to participate in the parent `<d2l-form>`.
|
|
4
|
+
|
|
5
|
+
## Usage
|
|
6
|
+
|
|
7
|
+
Simply extend the `FormElementContainerMixin`:
|
|
8
|
+
|
|
9
|
+
```javascript
|
|
10
|
+
import { FormElementContainerMixin } from '@brightspace-ui/core/form/form-element-container-mixin.js';
|
|
11
|
+
|
|
12
|
+
class MyCustomFormElementContainer extends FormElementContainerMixin(LitElement) {
|
|
13
|
+
render() {
|
|
14
|
+
html`
|
|
15
|
+
<d2l-input-text
|
|
16
|
+
label="First Name"
|
|
17
|
+
name="first-name"
|
|
18
|
+
required></d2l-input-text>
|
|
19
|
+
<d2l-input-text
|
|
20
|
+
label="Last Name"
|
|
21
|
+
name="last-name"
|
|
22
|
+
required></d2l-input-text>
|
|
23
|
+
`;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
customElements.define('my-custom-form-element-container', MyCustomFormElementContainer);
|
|
28
|
+
```
|
|
@@ -15,24 +15,34 @@ export const isElement = (node) => node && node.nodeType === Node.ELEMENT_NODE;
|
|
|
15
15
|
|
|
16
16
|
export const isCustomElement = (node) => isElement(node) && node.nodeName.indexOf('-') !== -1;
|
|
17
17
|
|
|
18
|
-
export const isCustomFormElement = (node) => isCustomElement(node) &&
|
|
18
|
+
export const isCustomFormElement = (node) => isCustomElement(node) && Boolean(node.formAssociated);
|
|
19
|
+
|
|
20
|
+
export const isCustomFormElementContainer = (node) => isCustomElement(node) && Boolean(node.isCustomFormElementContainer);
|
|
19
21
|
|
|
20
22
|
export const isNativeFormElement = (node) => {
|
|
21
23
|
if (!isElement(node)) {
|
|
22
24
|
return false;
|
|
23
25
|
}
|
|
24
26
|
const nodeName = node.nodeName.toLowerCase();
|
|
25
|
-
return
|
|
27
|
+
return Boolean(formElements[nodeName]);
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
const getElementChildren = (elem) => {
|
|
31
|
+
if (isCustomFormElementContainer(elem)) {
|
|
32
|
+
return elem.shadowRoot.children;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return elem.tagName === 'SLOT' && ['primary', 'secondary'].includes(elem.name) ? elem.assignedNodes() : elem.children;
|
|
26
36
|
};
|
|
27
37
|
|
|
28
|
-
const _findFormElementsHelper = (
|
|
29
|
-
if (isNativeFormElement(
|
|
30
|
-
|
|
38
|
+
const _findFormElementsHelper = (elem, elems, isFormElementPredicate, visitChildrenPredicate) => {
|
|
39
|
+
if (isNativeFormElement(elem) || isCustomFormElement(elem) || isFormElementPredicate(elem)) {
|
|
40
|
+
elems.push(elem);
|
|
31
41
|
}
|
|
32
|
-
if (visitChildrenPredicate(
|
|
33
|
-
const children =
|
|
42
|
+
if (visitChildrenPredicate(elem)) {
|
|
43
|
+
const children = getElementChildren(elem);
|
|
34
44
|
for (const child of children) {
|
|
35
|
-
_findFormElementsHelper(child,
|
|
45
|
+
_findFormElementsHelper(child, elems, isFormElementPredicate, visitChildrenPredicate);
|
|
36
46
|
}
|
|
37
47
|
}
|
|
38
48
|
};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import '../colors/colors.js';
|
|
2
2
|
import '../skip-nav/skip-nav-main.js';
|
|
3
3
|
import { css, html, LitElement, nothing } from 'lit';
|
|
4
|
+
import { classMap } from 'lit/directives/class-map.js';
|
|
4
5
|
import { getNextFocusable } from '../../helpers/focus.js';
|
|
5
6
|
|
|
6
7
|
export const isWindows = window.navigator.userAgent.indexOf('Windows') > -1;
|
|
@@ -17,6 +18,11 @@ class PageHeaderCustom extends LitElement {
|
|
|
17
18
|
|
|
18
19
|
static get properties() {
|
|
19
20
|
return {
|
|
21
|
+
/**
|
|
22
|
+
* When set, the bottom slot will be a "d2l-visible-on-ancestor-target"
|
|
23
|
+
* @type {boolean}
|
|
24
|
+
*/
|
|
25
|
+
bottomIsVisibleOnAncestorTarget: { type: Boolean, attribute: 'bottom-is-visible-on-ancestor-target' },
|
|
20
26
|
/**
|
|
21
27
|
* Whether to render a skip nav link
|
|
22
28
|
* @type {boolean}
|
|
@@ -132,6 +138,7 @@ class PageHeaderCustom extends LitElement {
|
|
|
132
138
|
|
|
133
139
|
constructor() {
|
|
134
140
|
super();
|
|
141
|
+
this.bottomIsVisibleOnAncestorTarget = false;
|
|
135
142
|
this.hasSkipNav = false;
|
|
136
143
|
this._hasBottom = false;
|
|
137
144
|
}
|
|
@@ -187,8 +194,12 @@ class PageHeaderCustom extends LitElement {
|
|
|
187
194
|
}
|
|
188
195
|
|
|
189
196
|
#renderBottom() {
|
|
197
|
+
const bottomClasses = {
|
|
198
|
+
bottom: true,
|
|
199
|
+
'd2l-visible-on-ancestor-target': this.bottomIsVisibleOnAncestorTarget
|
|
200
|
+
};
|
|
190
201
|
return html`
|
|
191
|
-
<div class="
|
|
202
|
+
<div class="${classMap(bottomClasses)}" ?hidden="${!this._hasBottom}">
|
|
192
203
|
<div class="max-width">
|
|
193
204
|
<div class="padding">
|
|
194
205
|
<slot name="bottom" @slotchange="${this.#handleBottomSlotChange}"></slot>
|
package/custom-elements.json
CHANGED
|
@@ -4967,6 +4967,21 @@
|
|
|
4967
4967
|
}
|
|
4968
4968
|
]
|
|
4969
4969
|
},
|
|
4970
|
+
{
|
|
4971
|
+
"name": "d2l-custom-form-element-container",
|
|
4972
|
+
"path": "./components/form/demo/custom-form-element-container.js",
|
|
4973
|
+
"properties": [
|
|
4974
|
+
{
|
|
4975
|
+
"name": "styles",
|
|
4976
|
+
"type": "CSSResult[]",
|
|
4977
|
+
"default": "[\"inputStyles\",\"inputLabelStyles\"]"
|
|
4978
|
+
},
|
|
4979
|
+
{
|
|
4980
|
+
"name": "isCustomFormElementContainer",
|
|
4981
|
+
"type": "boolean"
|
|
4982
|
+
}
|
|
4983
|
+
]
|
|
4984
|
+
},
|
|
4970
4985
|
{
|
|
4971
4986
|
"name": "d2l-form-demo",
|
|
4972
4987
|
"path": "./components/form/demo/form-demo.js"
|
|
@@ -12444,6 +12459,12 @@
|
|
|
12444
12459
|
"path": "./components/page/page-header-custom.js",
|
|
12445
12460
|
"description": "Generic page header layout component",
|
|
12446
12461
|
"attributes": [
|
|
12462
|
+
{
|
|
12463
|
+
"name": "bottom-is-visible-on-ancestor-target",
|
|
12464
|
+
"description": "When set, the bottom slot will be a \"d2l-visible-on-ancestor-target\"",
|
|
12465
|
+
"type": "boolean",
|
|
12466
|
+
"default": "false"
|
|
12467
|
+
},
|
|
12447
12468
|
{
|
|
12448
12469
|
"name": "has-skip-nav",
|
|
12449
12470
|
"description": "Whether to render a skip nav link",
|
|
@@ -12452,6 +12473,13 @@
|
|
|
12452
12473
|
}
|
|
12453
12474
|
],
|
|
12454
12475
|
"properties": [
|
|
12476
|
+
{
|
|
12477
|
+
"name": "bottomIsVisibleOnAncestorTarget",
|
|
12478
|
+
"attribute": "bottom-is-visible-on-ancestor-target",
|
|
12479
|
+
"description": "When set, the bottom slot will be a \"d2l-visible-on-ancestor-target\"",
|
|
12480
|
+
"type": "boolean",
|
|
12481
|
+
"default": "false"
|
|
12482
|
+
},
|
|
12455
12483
|
{
|
|
12456
12484
|
"name": "hasSkipNav",
|
|
12457
12485
|
"attribute": "has-skip-nav",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@brightspace-ui/core",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.256.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",
|