@brightspace-ui/core 2.165.0 → 2.167.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/empty-state/empty-state-action-button.js +3 -23
- package/components/empty-state/empty-state-action-link.js +4 -36
- package/components/empty-state/empty-state-illustrated.js +4 -35
- package/components/empty-state/empty-state-simple.js +3 -27
- package/components/inputs/input-text.js +14 -21
- package/package.json +1 -1
- package/tools/dom-test-helpers.js +0 -28
@@ -2,13 +2,14 @@ import '../button/button.js';
|
|
2
2
|
import '../button/button-subtle.js';
|
3
3
|
import { css, html, LitElement, nothing } from 'lit';
|
4
4
|
import { ifDefined } from 'lit/directives/if-defined.js';
|
5
|
+
import { PropertyRequiredMixin } from '../../mixins/property-required/property-required-mixin.js';
|
5
6
|
|
6
7
|
/**
|
7
8
|
* `d2l-empty-state-action-button` is an empty state action component that can be placed inside of the default slot of `empty-state-simple` or `empty-state-illustrated` to add a button action to the component.
|
8
9
|
* @fires d2l-empty-state-action - Dispatched when the action button is clicked
|
9
10
|
* @fires d2l-empty-state-illustrated-check - Internal event
|
10
11
|
*/
|
11
|
-
class EmptyStateActionButton extends LitElement {
|
12
|
+
class EmptyStateActionButton extends PropertyRequiredMixin(LitElement) {
|
12
13
|
|
13
14
|
static get properties() {
|
14
15
|
return {
|
@@ -16,7 +17,7 @@ class EmptyStateActionButton extends LitElement {
|
|
16
17
|
* REQUIRED: The action text to be used in the button
|
17
18
|
* @type {string}
|
18
19
|
*/
|
19
|
-
text: { type: String },
|
20
|
+
text: { type: String, required: true },
|
20
21
|
/**
|
21
22
|
* This will change the action button to use a primary button instead of the default subtle button. The primary attribute is only valid when `d2l-empty-state-action-button` is placed within `d2l-empty-state-illustrated` components
|
22
23
|
* @type {boolean}
|
@@ -37,8 +38,6 @@ class EmptyStateActionButton extends LitElement {
|
|
37
38
|
constructor() {
|
38
39
|
super();
|
39
40
|
this._illustrated = false;
|
40
|
-
this._missingTextErrorHasBeenThrown = false;
|
41
|
-
this._validatingTextTimeout = null;
|
42
41
|
}
|
43
42
|
|
44
43
|
connectedCallback() {
|
@@ -53,11 +52,6 @@ class EmptyStateActionButton extends LitElement {
|
|
53
52
|
});
|
54
53
|
}
|
55
54
|
|
56
|
-
firstUpdated(changedProperties) {
|
57
|
-
super.firstUpdated(changedProperties);
|
58
|
-
this._validateText();
|
59
|
-
}
|
60
|
-
|
61
55
|
render() {
|
62
56
|
let actionButton = nothing;
|
63
57
|
if (this.text) {
|
@@ -84,20 +78,6 @@ class EmptyStateActionButton extends LitElement {
|
|
84
78
|
this.dispatchEvent(new CustomEvent('d2l-empty-state-action'));
|
85
79
|
}
|
86
80
|
|
87
|
-
_validateText() {
|
88
|
-
clearTimeout(this._validatingTextTimeout);
|
89
|
-
// don't error immediately in case it doesn't get set immediately
|
90
|
-
this._validatingTextTimeout = setTimeout(() => {
|
91
|
-
this._validatingTextTimeout = null;
|
92
|
-
const hasText = (typeof this.text === 'string') && this.text.length > 0;
|
93
|
-
|
94
|
-
if (!hasText && !this._missingTextErrorHasBeenThrown) {
|
95
|
-
this._missingTextErrorHasBeenThrown = true;
|
96
|
-
setTimeout(() => { throw new Error('<d2l-empty-state-action-button>: missing required "text" attribute.'); });
|
97
|
-
}
|
98
|
-
}, 3000);
|
99
|
-
}
|
100
|
-
|
101
81
|
}
|
102
82
|
|
103
83
|
customElements.define('d2l-empty-state-action-button', EmptyStateActionButton);
|
@@ -1,11 +1,12 @@
|
|
1
1
|
import { html, LitElement, nothing } from 'lit';
|
2
2
|
import { bodyCompactStyles } from '../typography/styles.js';
|
3
3
|
import { linkStyles } from '../link/link.js';
|
4
|
+
import { PropertyRequiredMixin } from '../../mixins/property-required/property-required-mixin.js';
|
4
5
|
|
5
6
|
/**
|
6
7
|
* `d2l-empty-state-action-link` is an empty state action component that can be placed inside of the default slot of `empty-state-simple` or `empty-state-illustrated` to add a link action to the component.
|
7
8
|
*/
|
8
|
-
class EmptyStateActionLink extends LitElement {
|
9
|
+
class EmptyStateActionLink extends PropertyRequiredMixin(LitElement) {
|
9
10
|
|
10
11
|
static get properties() {
|
11
12
|
return {
|
@@ -13,12 +14,12 @@ class EmptyStateActionLink extends LitElement {
|
|
13
14
|
* REQUIRED: The action text to be used in the subtle button
|
14
15
|
* @type {string}
|
15
16
|
*/
|
16
|
-
text: { type: String },
|
17
|
+
text: { type: String, required: true },
|
17
18
|
/**
|
18
19
|
* REQUIRED: The action URL or URL fragment of the link
|
19
20
|
* @type {string}
|
20
21
|
*/
|
21
|
-
href: { type: String },
|
22
|
+
href: { type: String, required: true },
|
22
23
|
};
|
23
24
|
}
|
24
25
|
|
@@ -26,18 +27,6 @@ class EmptyStateActionLink extends LitElement {
|
|
26
27
|
return [bodyCompactStyles, linkStyles];
|
27
28
|
}
|
28
29
|
|
29
|
-
constructor() {
|
30
|
-
super();
|
31
|
-
this._missingHrefErrorHasBeenThrown = false;
|
32
|
-
this._missingTextErrorHasBeenThrown = false;
|
33
|
-
this._validatingAttributesTimeout = null;
|
34
|
-
}
|
35
|
-
|
36
|
-
firstUpdated(changedProperties) {
|
37
|
-
super.firstUpdated(changedProperties);
|
38
|
-
this._validateAttributes();
|
39
|
-
}
|
40
|
-
|
41
30
|
render() {
|
42
31
|
const actionLink = this.text && this.href
|
43
32
|
? html`
|
@@ -47,27 +36,6 @@ class EmptyStateActionLink extends LitElement {
|
|
47
36
|
return html`${actionLink}`;
|
48
37
|
}
|
49
38
|
|
50
|
-
_validateAttributes() {
|
51
|
-
clearTimeout(this._validatingAttributesTimeout);
|
52
|
-
// don't error immediately in case it doesn't get set immediately
|
53
|
-
this._validatingAttributesTimeout = setTimeout(() => {
|
54
|
-
this._validatingAttributesTimeout = null;
|
55
|
-
|
56
|
-
const hasHref = (typeof this.href === 'string') && this.href.length > 0;
|
57
|
-
const hasText = (typeof this.text === 'string') && this.text.length > 0;
|
58
|
-
|
59
|
-
if (!hasHref && !this._missingHrefErrorHasBeenThrown) {
|
60
|
-
this._missingHrefErrorHasBeenThrown = true;
|
61
|
-
setTimeout(() => { throw new Error('<d2l-empty-state-action-link>: missing required "href" attribute.'); });
|
62
|
-
}
|
63
|
-
|
64
|
-
if (!hasText && !this._missingTextErrorHasBeenThrown) {
|
65
|
-
this._missingTextErrorHasBeenThrown = true;
|
66
|
-
setTimeout(() => { throw new Error('<d2l-empty-state-action-link>: missing required "text" attribute.'); });
|
67
|
-
}
|
68
|
-
}, 3000);
|
69
|
-
}
|
70
|
-
|
71
39
|
}
|
72
40
|
|
73
41
|
customElements.define('d2l-empty-state-action-link', EmptyStateActionLink);
|
@@ -3,6 +3,7 @@ import { html, LitElement, nothing } from 'lit';
|
|
3
3
|
import { bodyCompactStyles } from '../typography/styles.js';
|
4
4
|
import { classMap } from 'lit/directives/class-map.js';
|
5
5
|
import { loadSvg } from '../../generated/empty-state/presetIllustrationLoader.js';
|
6
|
+
import { PropertyRequiredMixin } from '../../mixins/property-required/property-required-mixin.js';
|
6
7
|
import ResizeObserver from 'resize-observer-polyfill/dist/ResizeObserver.es.js';
|
7
8
|
import { runAsync } from '../../directives/run-async/run-async.js';
|
8
9
|
import { styleMap } from 'lit/directives/style-map.js';
|
@@ -15,7 +16,7 @@ const illustrationAspectRatio = 500 / 330;
|
|
15
16
|
* @slot - Slot for empty state actions
|
16
17
|
* @slot illustration - Slot for custom SVG content if `illustration-name` property is not set
|
17
18
|
*/
|
18
|
-
class EmptyStateIllustrated extends LitElement {
|
19
|
+
class EmptyStateIllustrated extends PropertyRequiredMixin(LitElement) {
|
19
20
|
|
20
21
|
static get properties() {
|
21
22
|
return {
|
@@ -23,7 +24,7 @@ class EmptyStateIllustrated extends LitElement {
|
|
23
24
|
* REQUIRED: A description giving details about the empty state
|
24
25
|
* @type {string}
|
25
26
|
*/
|
26
|
-
description: { type: String },
|
27
|
+
description: { type: String, required: true },
|
27
28
|
/**
|
28
29
|
* The name of the preset image you would like to display in the component
|
29
30
|
* @type {string}
|
@@ -33,7 +34,7 @@ class EmptyStateIllustrated extends LitElement {
|
|
33
34
|
* REQUIRED: A title for the empty state
|
34
35
|
* @type {string}
|
35
36
|
*/
|
36
|
-
titleText: { type: String, attribute: 'title-text' },
|
37
|
+
titleText: { type: String, attribute: 'title-text', required: true },
|
37
38
|
_contentHeight: { state: true },
|
38
39
|
_titleSmall: { state: true }
|
39
40
|
};
|
@@ -46,11 +47,8 @@ class EmptyStateIllustrated extends LitElement {
|
|
46
47
|
constructor() {
|
47
48
|
super();
|
48
49
|
this._contentHeight = 330;
|
49
|
-
this._missingDescriptionErrorHasBeenThrown = false;
|
50
|
-
this._missingTitleTextErrorHasBeenThrown = false;
|
51
50
|
this._resizeObserver = new ResizeObserver(this._onResize.bind(this));
|
52
51
|
this._titleSmall = false;
|
53
|
-
this._validatingAttributesTimeout = null;
|
54
52
|
}
|
55
53
|
|
56
54
|
connectedCallback() {
|
@@ -65,11 +63,6 @@ class EmptyStateIllustrated extends LitElement {
|
|
65
63
|
this._resizeObserver.disconnect();
|
66
64
|
}
|
67
65
|
|
68
|
-
firstUpdated(changedProperties) {
|
69
|
-
super.firstUpdated(changedProperties);
|
70
|
-
this._validateAttributes();
|
71
|
-
}
|
72
|
-
|
73
66
|
render() {
|
74
67
|
const illustrationContainerStyle = this._getIllustrationContainerStyle();
|
75
68
|
const titleClass = this._getTitleClass();
|
@@ -126,30 +119,6 @@ class EmptyStateIllustrated extends LitElement {
|
|
126
119
|
});
|
127
120
|
}
|
128
121
|
|
129
|
-
_validateAttributes() {
|
130
|
-
clearTimeout(this._validatingAttributesTimeout);
|
131
|
-
// don't error immediately in case it doesn't get set immediately
|
132
|
-
this._validatingAttributesTimeout = setTimeout(() => {
|
133
|
-
this._validatingAttributesTimeout = null;
|
134
|
-
const hasTitleText = (typeof this.titleText === 'string') && this.titleText.length > 0;
|
135
|
-
const hasDescription = (typeof this.description === 'string') && this.description.length > 0;
|
136
|
-
|
137
|
-
if (!hasTitleText && !this._missingTitleTextErrorHasBeenThrown) {
|
138
|
-
this._missingTitleTextErrorHasBeenThrown = true;
|
139
|
-
setTimeout(() => {
|
140
|
-
throw new Error('<d2l-empty-state-illustrated>: missing required "titleText" attribute.');
|
141
|
-
});
|
142
|
-
}
|
143
|
-
|
144
|
-
if (!hasDescription && !this._missingDescriptionErrorHasBeenThrown) {
|
145
|
-
this._missingDescriptionErrorHasBeenThrown = true;
|
146
|
-
setTimeout(() => {
|
147
|
-
throw new Error('<d2l-empty-state-illustrated>: missing required "description" attribute.');
|
148
|
-
});
|
149
|
-
}
|
150
|
-
}, 3000);
|
151
|
-
}
|
152
|
-
|
153
122
|
}
|
154
123
|
|
155
124
|
customElements.define('d2l-empty-state-illustrated', EmptyStateIllustrated);
|
@@ -2,13 +2,14 @@ import '../button/button-subtle.js';
|
|
2
2
|
import { emptyStateSimpleStyles, emptyStateStyles } from './empty-state-styles.js';
|
3
3
|
import { html, LitElement } from 'lit';
|
4
4
|
import { bodyCompactStyles } from '../typography/styles.js';
|
5
|
+
import { PropertyRequiredMixin } from '../../mixins/property-required/property-required-mixin.js';
|
5
6
|
import { RtlMixin } from '../../mixins/rtl/rtl-mixin.js';
|
6
7
|
|
7
8
|
/**
|
8
9
|
* The `d2l-empty-state-simple` component is an empty state component that displays a description. An empty state action component can be placed inside of the default slot to add an optional action.
|
9
10
|
* @slot - Slot for empty state actions
|
10
11
|
*/
|
11
|
-
class EmptyStateSimple extends RtlMixin(LitElement) {
|
12
|
+
class EmptyStateSimple extends PropertyRequiredMixin(RtlMixin(LitElement)) {
|
12
13
|
|
13
14
|
static get properties() {
|
14
15
|
return {
|
@@ -16,7 +17,7 @@ class EmptyStateSimple extends RtlMixin(LitElement) {
|
|
16
17
|
* REQUIRED: A description giving details about the empty state
|
17
18
|
* @type {string}
|
18
19
|
*/
|
19
|
-
description: { type: String },
|
20
|
+
description: { type: String, required: true },
|
20
21
|
};
|
21
22
|
}
|
22
23
|
|
@@ -24,17 +25,6 @@ class EmptyStateSimple extends RtlMixin(LitElement) {
|
|
24
25
|
return [bodyCompactStyles, emptyStateStyles, emptyStateSimpleStyles];
|
25
26
|
}
|
26
27
|
|
27
|
-
constructor() {
|
28
|
-
super();
|
29
|
-
this._missingDescriptionErrorHasBeenThrown = false;
|
30
|
-
this._validatingDescriptionTimeout = null;
|
31
|
-
}
|
32
|
-
|
33
|
-
firstUpdated(changedProperties) {
|
34
|
-
super.firstUpdated(changedProperties);
|
35
|
-
this._validateDescription();
|
36
|
-
}
|
37
|
-
|
38
28
|
render() {
|
39
29
|
return html`
|
40
30
|
<p class="d2l-body-compact d2l-empty-state-description">${this.description}</p>
|
@@ -42,20 +32,6 @@ class EmptyStateSimple extends RtlMixin(LitElement) {
|
|
42
32
|
`;
|
43
33
|
}
|
44
34
|
|
45
|
-
_validateDescription() {
|
46
|
-
clearTimeout(this._validatingDescriptionTimeout);
|
47
|
-
// don't error immediately in case it doesn't get set immediately
|
48
|
-
this._validatingDescriptionTimeout = setTimeout(() => {
|
49
|
-
this._validatingDescriptionTimeout = null;
|
50
|
-
const hasDescription = (typeof this.description === 'string') && this.description.length > 0;
|
51
|
-
|
52
|
-
if (!hasDescription && !this._missingDescriptionErrorHasBeenThrown) {
|
53
|
-
this._missingDescriptionErrorHasBeenThrown = true;
|
54
|
-
setTimeout(() => { throw new Error('<d2l-empty-state-simple>: missing required "description" attribute.'); });
|
55
|
-
}
|
56
|
-
}, 3000);
|
57
|
-
}
|
58
|
-
|
59
35
|
}
|
60
36
|
|
61
37
|
customElements.define('d2l-empty-state-simple', EmptyStateSimple);
|
@@ -12,6 +12,7 @@ import { inputStyles } from './input-styles.js';
|
|
12
12
|
import { LabelledMixin } from '../../mixins/labelled/labelled-mixin.js';
|
13
13
|
import { offscreenStyles } from '../offscreen/offscreen.js';
|
14
14
|
import { PerfMonitor } from '../../helpers/perfMonitor.js';
|
15
|
+
import { PropertyRequiredMixin } from '../../mixins/property-required/property-required-mixin.js';
|
15
16
|
import { RtlMixin } from '../../mixins/rtl/rtl-mixin.js';
|
16
17
|
import { SkeletonMixin } from '../skeleton/skeleton-mixin.js';
|
17
18
|
import { styleMap } from 'lit/directives/style-map.js';
|
@@ -24,7 +25,7 @@ import { styleMap } from 'lit/directives/style-map.js';
|
|
24
25
|
* @fires change - Dispatched when an alteration to the value is committed (typically after focus is lost) by the user
|
25
26
|
* @fires input - Dispatched immediately after changes by the user
|
26
27
|
*/
|
27
|
-
class InputText extends FocusMixin(LabelledMixin(FormElementMixin(SkeletonMixin(RtlMixin(LitElement))))) {
|
28
|
+
class InputText extends PropertyRequiredMixin(FocusMixin(LabelledMixin(FormElementMixin(SkeletonMixin(RtlMixin(LitElement)))))) {
|
28
29
|
|
29
30
|
static get properties() {
|
30
31
|
return {
|
@@ -152,7 +153,18 @@ class InputText extends FocusMixin(LabelledMixin(FormElementMixin(SkeletonMixin(
|
|
152
153
|
* Accessible label for the unit which will not be visually rendered
|
153
154
|
* @type {string}
|
154
155
|
*/
|
155
|
-
unitLabel: {
|
156
|
+
unitLabel: {
|
157
|
+
attribute: 'unit-label',
|
158
|
+
required: {
|
159
|
+
dependentProps: ['unit'],
|
160
|
+
message: (_value, elem) => `<d2l-input-text>: missing required attribute "unit-label" for unit "${elem.unit}"`,
|
161
|
+
validator: (_value, elem, hasValue) => {
|
162
|
+
const hasUnit = (typeof elem.unit === 'string') && elem.unit.length > 0;
|
163
|
+
return !(hasUnit && elem.unit !== '%' && !hasValue);
|
164
|
+
}
|
165
|
+
},
|
166
|
+
type: String
|
167
|
+
},
|
156
168
|
/**
|
157
169
|
* Value of the input
|
158
170
|
* @type {string}
|
@@ -270,7 +282,6 @@ class InputText extends FocusMixin(LabelledMixin(FormElementMixin(SkeletonMixin(
|
|
270
282
|
this._intersectionObserver = null;
|
271
283
|
this._isIntersecting = false;
|
272
284
|
this._lastSlotWidth = 0;
|
273
|
-
this._missingUnitLabelErrorHasBeenThrown = false;
|
274
285
|
this._prevValue = '';
|
275
286
|
|
276
287
|
this._handleBlur = this._handleBlur.bind(this);
|
@@ -278,7 +289,6 @@ class InputText extends FocusMixin(LabelledMixin(FormElementMixin(SkeletonMixin(
|
|
278
289
|
this._handleMouseEnter = this._handleMouseEnter.bind(this);
|
279
290
|
this._handleMouseLeave = this._handleMouseLeave.bind(this);
|
280
291
|
this._perfMonitor = new PerfMonitor(this);
|
281
|
-
this._validatingUnitTimeout = null;
|
282
292
|
}
|
283
293
|
|
284
294
|
get value() { return this._value; }
|
@@ -355,7 +365,6 @@ class InputText extends FocusMixin(LabelledMixin(FormElementMixin(SkeletonMixin(
|
|
355
365
|
super.firstUpdated(changedProperties);
|
356
366
|
|
357
367
|
this._setValue(this.value, true);
|
358
|
-
this._validateUnit();
|
359
368
|
|
360
369
|
const container = this.shadowRoot && this.shadowRoot.querySelector('.d2l-input-text-container');
|
361
370
|
if (!container) return;
|
@@ -484,7 +493,6 @@ class InputText extends FocusMixin(LabelledMixin(FormElementMixin(SkeletonMixin(
|
|
484
493
|
changedProperties.forEach((oldVal, prop) => {
|
485
494
|
if (prop === 'unit' || prop === 'unitLabel') {
|
486
495
|
this._updateInputLayout();
|
487
|
-
this._validateUnit();
|
488
496
|
} else if (prop === 'validationError') {
|
489
497
|
if (oldVal && this.validationError) {
|
490
498
|
const tooltip = this.shadowRoot.querySelector('d2l-tooltip');
|
@@ -655,20 +663,5 @@ class InputText extends FocusMixin(LabelledMixin(FormElementMixin(SkeletonMixin(
|
|
655
663
|
|
656
664
|
}
|
657
665
|
|
658
|
-
_validateUnit() {
|
659
|
-
if (this._missingUnitLabelErrorHasBeenThrown) return;
|
660
|
-
clearTimeout(this._validatingUnitTimeout);
|
661
|
-
// don't error immediately in case it doesn't get set immediately
|
662
|
-
this._validatingUnitTimeout = setTimeout(() => {
|
663
|
-
this._validatingUnitTimeout = null;
|
664
|
-
const hasUnit = (typeof this.unit === 'string') && this.unit.length > 0;
|
665
|
-
const hasUnitLabel = (typeof this.unitLabel === 'string') && this.unitLabel.length > 0;
|
666
|
-
if (hasUnit && this.unit !== '%' && !hasUnitLabel) {
|
667
|
-
this._missingUnitLabelErrorHasBeenThrown = true;
|
668
|
-
throw new Error(`<d2l-input-text>: missing required attribute "unit-label" for unit "${this.unit}"`);
|
669
|
-
}
|
670
|
-
}, 3000);
|
671
|
-
}
|
672
|
-
|
673
666
|
}
|
674
667
|
customElements.define('d2l-input-text', InputText);
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@brightspace-ui/core",
|
3
|
-
"version": "2.
|
3
|
+
"version": "2.167.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",
|
@@ -1,28 +0,0 @@
|
|
1
|
-
import { getComposedChildren } from '../helpers/dom.js';
|
2
|
-
|
3
|
-
export function keyDown(element, keyCode) {
|
4
|
-
const event = new CustomEvent('keydown', {
|
5
|
-
detail: 0,
|
6
|
-
bubbles: true,
|
7
|
-
cancelable: true,
|
8
|
-
composed: true
|
9
|
-
});
|
10
|
-
event.keyCode = keyCode;
|
11
|
-
event.code = keyCode;
|
12
|
-
element.dispatchEvent(event);
|
13
|
-
}
|
14
|
-
|
15
|
-
export async function getUpdateCompleteAll(node) {
|
16
|
-
|
17
|
-
if (!node || (node.nodeType !== Node.ELEMENT_NODE && node.nodeType !== Node.DOCUMENT_NODE && node.nodeType !== Node.DOCUMENT_FRAGMENT_NODE)) {
|
18
|
-
throw new TypeError('Invalid node. Must be nodeType document, element or document fragment');
|
19
|
-
}
|
20
|
-
|
21
|
-
const getUpdateComplete = async elem => {
|
22
|
-
if (elem.updateComplete) await elem.updateComplete;
|
23
|
-
const childElements = getComposedChildren(elem);
|
24
|
-
await Promise.all(childElements.map(childElement => getUpdateComplete(childElement)));
|
25
|
-
};
|
26
|
-
|
27
|
-
return getUpdateComplete(node);
|
28
|
-
}
|