@brightspace-ui/core 2.34.2 → 2.35.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.
Files changed (37) hide show
  1. package/components/empty-state/README.md +100 -0
  2. package/components/empty-state/demo/empty-state.html +54 -0
  3. package/components/empty-state/empty-state-illustrated-button.js +71 -0
  4. package/components/empty-state/empty-state-illustrated-link.js +57 -0
  5. package/components/empty-state/empty-state-illustrated-mixin.js +126 -0
  6. package/components/empty-state/empty-state-simple-button.js +82 -0
  7. package/components/empty-state/empty-state-simple-link.js +74 -0
  8. package/components/empty-state/empty-state-styles.js +84 -0
  9. package/components/empty-state/images/assembly-line.svg +133 -0
  10. package/components/empty-state/images/blueprint.svg +67 -0
  11. package/components/empty-state/images/calendar.svg +37 -0
  12. package/components/empty-state/images/cat-computer.svg +60 -0
  13. package/components/empty-state/images/checklist.svg +33 -0
  14. package/components/empty-state/images/data-tracking.svg +91 -0
  15. package/components/empty-state/images/desert-road.svg +134 -0
  16. package/components/empty-state/images/fish-hook.svg +143 -0
  17. package/components/empty-state/images/oven.svg +75 -0
  18. package/components/empty-state/images/pipeline.svg +126 -0
  19. package/components/empty-state/images/race.svg +199 -0
  20. package/components/empty-state/images/rockets.svg +698 -0
  21. package/components/empty-state/images/tumbleweed.svg +34 -0
  22. package/custom-elements.json +225 -0
  23. package/generated/empty-state/assembly-line.js +135 -0
  24. package/generated/empty-state/blueprint.js +69 -0
  25. package/generated/empty-state/calendar.js +39 -0
  26. package/generated/empty-state/cat-computer.js +62 -0
  27. package/generated/empty-state/checklist.js +35 -0
  28. package/generated/empty-state/data-tracking.js +93 -0
  29. package/generated/empty-state/desert-road.js +136 -0
  30. package/generated/empty-state/fish-hook.js +145 -0
  31. package/generated/empty-state/oven.js +77 -0
  32. package/generated/empty-state/pipeline.js +128 -0
  33. package/generated/empty-state/presetIllustrationLoader.js +32 -0
  34. package/generated/empty-state/race.js +201 -0
  35. package/generated/empty-state/rockets.js +700 -0
  36. package/generated/empty-state/tumbleweed.js +36 -0
  37. package/package.json +3 -2
@@ -0,0 +1,100 @@
1
+ # Empty State
2
+ Empty states are used when there is no data available to be displayed, or when a search or filter returns no results.
3
+
4
+ <!-- docs: demo align:start -->
5
+ ```html
6
+ <script type="module">
7
+ import '@brightspace-ui/core/components/empty-state/empty-state-simple-button.js';
8
+ import '@brightspace-ui/core/components/empty-state/empty-state-illustrated-button.js';
9
+ </script>
10
+
11
+ <d2l-empty-state-simple-button description="There are no assignments to display." action-text="Create an Assignment"></d2l-empty-state-simple-button>
12
+ <d2l-empty-state-illustrated-button illustration-name="desert-road" title-text="No Learning Paths Yet" description="Get started by clicking below to create your first learning path." action-text="Create Learning Paths"> </d2l-empty-state-illustrated-button>
13
+
14
+ ```
15
+
16
+ ## Best Practices
17
+
18
+ <!-- docs: start best practices -->
19
+ <!-- docs: start dos -->
20
+ * Do make it clear that there is no data available to be displayed
21
+ * Do include guidance on next steps if available, either as short instructions or as Call to Actions
22
+ * Do use a link for navigation and a button for actions
23
+ * Do replace the entire content with its empty state for accessibility
24
+ <!-- docs: end dos -->
25
+
26
+ <!-- docs: start donts -->
27
+ * Don’t use an empty state as a default state while data is loading
28
+ * Don't leave a section completely empty, or use a skeleton loading screen in place of an empty state component
29
+ * Avoid causing users to believe that they have hit a dead-end when they have not
30
+ <!-- docs: end donts -->
31
+ <!-- docs: end best practices -->
32
+
33
+ ## Empty State Simple Button [d2l-empty-state-simple-button]
34
+
35
+ The `d2l-empty-state-simple-button` component is an empty state component that displays a description and action button.
36
+
37
+ <!-- docs: demo live name:d2l-empty-state-simple-button -->
38
+ ```html
39
+ <script type="module">
40
+ import '@brightspace-ui/core/components/empty-state/empty-state-simple-button.js';
41
+ </script>
42
+
43
+ <d2l-empty-state-simple-button description="There are no assignments to display." action-text="Create an Assignment"></d2l-empty-state-simple-button>
44
+ ```
45
+
46
+ ## Empty State Simple Link [d2l-empty-state-simple-link]
47
+
48
+ The `d2l-empty-state-simple-link` component is an empty state component that displays a description and action link.
49
+
50
+ <!-- docs: demo live name:d2l-empty-state-simple-link -->
51
+ ```html
52
+ <script type="module">
53
+ import '@brightspace-ui/core/components/empty-state/empty-state-simple-link.js';
54
+ </script>
55
+
56
+ <d2l-empty-state-simple-link description="There are no assignments to display." action-text="Create an Assignment" action-href='https://d2l.com'></d2l-empty-state-simple-link>
57
+ ```
58
+ ## Empty State Illustrated Button [d2l-empty-state-illustrated-button]
59
+
60
+ The `d2l-empty-state-illustrated-button` component is an empty state component that displays a title and description with an illustration and action button. The `illustration-name` property can be set to use one of the preset illustrations or a custom SVG illustration can be added in the default slot.
61
+
62
+ <!-- docs: demo live name:d2l-empty-state-illustrated-button -->
63
+ ```html
64
+ <script type="module">
65
+ import '@brightspace-ui/core/components/empty-state/empty-state-illustrated-button.js';
66
+ </script>
67
+
68
+ <d2l-empty-state-illustrated-button illustration-name="desert-road" title-text="No Learning Paths Yet" description="Get started by clicking below to create your first learning path." action-text="Create Learning Paths"></d2l-empty-state-illustrated-button>
69
+ ```
70
+
71
+ ## Empty State Illustrated Link [d2l-empty-state-illustrated-link]
72
+
73
+ The `d2l-empty-state-illustrated-link` component is an empty state component that displays a title and description with an illustration and action link. The `illustration-name` property can be set to use one of the preset illustrations or a custom SVG illustration can be added in the default slot.
74
+
75
+ <!-- docs: demo live name:d2l-empty-state-illustrated-link -->
76
+ ```html
77
+ <script type="module">
78
+ import '@brightspace-ui/core/components/empty-state/empty-state-illustrated-link.js';
79
+ </script>
80
+
81
+ <d2l-empty-state-illustrated-link illustration-name="desert-road" title-text="No Learning Paths Yet" description="Get started by clicking below to create your first learning path." action-text="Create Learning Paths" action-href='https://d2l.com'></d2l-empty-state-illustrated-link>
82
+ ```
83
+
84
+ ## Preset Empty State Illustrations
85
+
86
+ | Illustration | Name |
87
+ | :---: | :--- |
88
+ | ![](https://raw.githubusercontent.com/BrightspaceUI/core/main/components/empty-state/images/assembly-line.svg?sanitize=true) | assembly-line |
89
+ | ![](https://raw.githubusercontent.com/BrightspaceUI/core/main/components/empty-state/images/blueprint.svg?sanitize=true) | blueprint |
90
+ | ![](https://raw.githubusercontent.com/BrightspaceUI/core/main/components/empty-state/images/calendar.svg?sanitize=true) | calendar |
91
+ | ![](https://raw.githubusercontent.com/BrightspaceUI/core/main/components/empty-state/images/cat-computer.svg?sanitize=true) | cat-computer |
92
+ | ![](https://raw.githubusercontent.com/BrightspaceUI/core/main/components/empty-state/images/checklist.svg?sanitize=true) | checklist |
93
+ | ![](https://raw.githubusercontent.com/BrightspaceUI/core/main/components/empty-state/images/data-tracking.svg?sanitize=true) | data-tracking |
94
+ | ![](https://raw.githubusercontent.com/BrightspaceUI/core/main/components/empty-state/images/desert-road.svg?sanitize=true) | desert-road |
95
+ | ![](https://raw.githubusercontent.com/BrightspaceUI/core/main/components/empty-state/images/fish-hook.svg?sanitize=true) | fish-hook |
96
+ | ![](https://raw.githubusercontent.com/BrightspaceUI/core/main/components/empty-state/images/oven.svg?sanitize=true) | oven |
97
+ | ![](https://raw.githubusercontent.com/BrightspaceUI/core/main/components/empty-state/images/pipeline.svg?sanitize=true) | pipeline |
98
+ | ![](https://raw.githubusercontent.com/BrightspaceUI/core/main/components/empty-state/images/race.svg?sanitize=true) | race |
99
+ | ![](https://raw.githubusercontent.com/BrightspaceUI/core/main/components/empty-state/images/rockets.svg?sanitize=true) | rockets |
100
+ | ![](https://raw.githubusercontent.com/BrightspaceUI/core/main/components/empty-state/images/tumbleweed.svg?sanitize=true) | tumbleweed |
@@ -0,0 +1,54 @@
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 '../empty-state-simple-button.js';
10
+ import '../empty-state-simple-link.js';
11
+ import '../empty-state-illustrated-button.js';
12
+ import '../empty-state-illustrated-link.js';
13
+ </script>
14
+ </head>
15
+ <body unresolved>
16
+
17
+ <d2l-demo-page page-title="d2l-empty-state">
18
+
19
+ <h2>Empty State Simple Button</h2>
20
+
21
+ <d2l-demo-snippet>
22
+ <template>
23
+ <d2l-empty-state-simple-button description="There are no assignments to display." action-text="Create New Assignment"></d2l-empty-state-simple-button>
24
+ </template>
25
+ </d2l-demo-snippet>
26
+
27
+ <h2>Empty State Simple Link</h2>
28
+
29
+ <d2l-demo-snippet>
30
+ <template>
31
+ <d2l-empty-state-simple-link description="There are no assignments to display." action-text="Create New Assignment" action-href="https://www.d2l.com/"></d2l-empty-state-simple-link>
32
+ </template>
33
+ </d2l-demo-snippet>
34
+
35
+ <h2>Empty State Illustrated Button</h2>
36
+
37
+ <d2l-demo-snippet>
38
+ <template>
39
+ <d2l-empty-state-illustrated-button illustration-name="fish-hook" title-text="No Learning Paths Yet" description="Get started by clicking below to create your first learning path." action-text="Create Learning Paths"></d2l-empty-state-illustrated-button>
40
+ </template>
41
+ </d2l-demo-snippet>
42
+
43
+ <h2>Empty State Illustrated Link</h2>
44
+
45
+ <d2l-demo-snippet>
46
+ <template>
47
+ <d2l-empty-state-illustrated-link illustration-name="desert-road" title-text="No Learning Paths Yet" description="Get started by clicking below to create your first learning path." action-text="Create Learning Paths" action-href="https://www.d2l.com/"></d2l-empty-state-illustrated-link>
48
+ </template>
49
+ </d2l-demo-snippet>
50
+
51
+ </d2l-demo-page>
52
+
53
+ </body>
54
+ </html>
@@ -0,0 +1,71 @@
1
+ import '../button/button.js';
2
+ import '../button/button-subtle.js';
3
+ import { html, LitElement, nothing } from 'lit';
4
+ import { classMap } from 'lit/directives/class-map.js';
5
+ import { EmptyStateIllustratedMixin } from './empty-state-illustrated-mixin.js';
6
+ import { runAsync } from '../../directives/run-async/run-async.js';
7
+ import { styleMap } from 'lit/directives/style-map.js';
8
+
9
+ /**
10
+ * The `d2l-empty-state-illustrated-button` component is an empty state component that displays an illustration and action button. The illustration property can be set to use one of the preset illustrations or a custom SVG illustration can be added in the default slot.
11
+ * @fires d2l-empty-state-action - Dispatched when the action button is clicked
12
+ * @slot - Custom SVG content if `illustration-name` property is not set
13
+ */
14
+ class EmptyStateIllustratedButton extends EmptyStateIllustratedMixin(LitElement) {
15
+
16
+ static get properties() {
17
+ return {
18
+ /**
19
+ * This will change the action button to use a primary button instead of the default subtle button
20
+ * @type {boolean}
21
+ */
22
+ primary: { type: Boolean },
23
+ };
24
+ }
25
+
26
+ constructor() {
27
+ super();
28
+ this._illustratedComponentType = 'button';
29
+ }
30
+
31
+ render() {
32
+ const illustrationContainerStyle = this.getIllustrationContainerStyle();
33
+ const titleClass = this.getTitleClass();
34
+
35
+ let actionButton = nothing;
36
+ if (this.actionText) {
37
+ actionButton = this.primary
38
+ ? html`<d2l-button
39
+ class="d2l-empty-state-action"
40
+ @click=${this._handleActionClick}
41
+ primary>${this.actionText}
42
+ </d2l-button>`
43
+ : html`<d2l-button-subtle
44
+ class="d2l-empty-state-action"
45
+ @click=${this._handleActionClick}
46
+ text=${this.actionText}>
47
+ </d2l-button-subtle>`;
48
+ }
49
+
50
+ return html`
51
+ ${this.illustrationName
52
+ ? html`
53
+ <div style="${styleMap(illustrationContainerStyle)}">
54
+ ${runAsync(this.illustrationName, () => this.getIllustration(this.illustrationName), { success: (illustration) => illustration }, { pendingState: false })}
55
+ </div>`
56
+ : html`<slot></slot>`}
57
+
58
+ <p class="${classMap(titleClass)}">${this.titleText}</p>
59
+ <p class="d2l-body-compact d2l-empty-state-description">${this.description}</p>
60
+ ${actionButton}
61
+ `;
62
+ }
63
+
64
+ _handleActionClick(e) {
65
+ e.stopPropagation();
66
+ this.dispatchEvent(new CustomEvent('d2l-empty-state-action'));
67
+ }
68
+
69
+ }
70
+
71
+ customElements.define('d2l-empty-state-illustrated-button', EmptyStateIllustratedButton);
@@ -0,0 +1,57 @@
1
+ import { html, LitElement, nothing } from 'lit';
2
+ import { classMap } from 'lit/directives/class-map.js';
3
+ import { EmptyStateIllustratedMixin } from './empty-state-illustrated-mixin.js';
4
+ import { linkStyles } from '../link/link.js';
5
+ import { runAsync } from '../../directives/run-async/run-async.js';
6
+ import { styleMap } from 'lit/directives/style-map.js';
7
+
8
+ /**
9
+ * The `d2l-empty-state-illustrated-link` component is an empty state component that displays an illustration and action link. The illustration property can be set to use one of the preset illustrations or a custom SVG illustration can be added in the default slot.
10
+ * @slot - Custom SVG content if `illustration-name` property is not set
11
+ */
12
+ class EmptyStateIllustratedLink extends EmptyStateIllustratedMixin(LitElement) {
13
+
14
+ static get properties() {
15
+ return {
16
+ /**
17
+ * The action URL or URL fragment of the link
18
+ * @type {string}
19
+ */
20
+ actionHref: { type: String, attribute: 'action-href' },
21
+ };
22
+ }
23
+
24
+ static get styles() {
25
+ return [super.styles, linkStyles];
26
+ }
27
+
28
+ constructor() {
29
+ super();
30
+ this._illustratedComponentType = 'link';
31
+ }
32
+
33
+ render() {
34
+ const illustrationContainerStyle = this.getIllustrationContainerStyle();
35
+ const titleClass = this.getTitleClass();
36
+
37
+ const actionLink = this.actionText && this.actionHref
38
+ ? html`<a class="d2l-body-compact d2l-empty-state-action d2l-link" href=${this.actionHref}>${this.actionText}</a>`
39
+ : nothing;
40
+
41
+ return html`
42
+ ${this.illustrationName
43
+ ? html`
44
+ <div style="${styleMap(illustrationContainerStyle)}">
45
+ ${runAsync(this.illustrationName, () => this.getIllustration(this.illustrationName), { success: (illustration) => illustration }, { pendingState: false })}
46
+ </div>`
47
+ : html`<slot></slot>`}
48
+
49
+ <p class="${classMap(titleClass)}">${this.titleText}</p>
50
+ <p class="d2l-body-compact d2l-empty-state-description">${this.description}</p>
51
+ ${actionLink}
52
+ `;
53
+ }
54
+
55
+ }
56
+
57
+ customElements.define('d2l-empty-state-illustrated-link', EmptyStateIllustratedLink);
@@ -0,0 +1,126 @@
1
+ import { emptyStateIllustratedStyles, emptyStateStyles } from './empty-state-styles.js';
2
+ import { html, nothing } from 'lit';
3
+ import { bodyCompactStyles } from '../typography/styles.js';
4
+ import { loadSvg } from '../../generated/empty-state/presetIllustrationLoader.js';
5
+ import ResizeObserver from 'resize-observer-polyfill/dist/ResizeObserver.es.js';
6
+ import { RtlMixin } from '../../mixins/rtl-mixin.js';
7
+ import { unsafeSVG } from 'lit/directives/unsafe-svg.js';
8
+
9
+ const illustrationAspectRatio = 500 / 330;
10
+
11
+ export const EmptyStateIllustratedMixin = superclass => class extends RtlMixin(superclass) {
12
+
13
+ static get properties() {
14
+ return {
15
+ /**
16
+ * The action text to be used in the subtle button
17
+ * @type {string}
18
+ */
19
+ actionText: { type: String, attribute: 'action-text' },
20
+ /**
21
+ * REQUIRED: A description giving details about the empty state
22
+ * @type {string}
23
+ */
24
+ description: { type: String },
25
+ /**
26
+ * The name of the preset image you would like to display in the component
27
+ * @type {string}
28
+ */
29
+ illustrationName: { type: String, attribute: 'illustration-name' },
30
+ /**
31
+ * REQUIRED: A title for the empty state
32
+ * @type {string}
33
+ */
34
+ titleText: { type: String, attribute: 'title-text' },
35
+ _contentHeight: { state: true },
36
+ _illustratedComponentType: { state: true },
37
+ _titleSmall: { state: true }
38
+ };
39
+ }
40
+
41
+ static get styles() {
42
+ return [bodyCompactStyles, emptyStateStyles, emptyStateIllustratedStyles];
43
+ }
44
+
45
+ constructor() {
46
+ super();
47
+
48
+ this._contentHeight = 330;
49
+ this._missingDescriptionErrorHasBeenThrown = false;
50
+ this._missingTitleTextErrorHasBeenThrown = false;
51
+ this._resizeObserver = new ResizeObserver(this._onResize.bind(this));
52
+ this._titleSmall = false;
53
+ this._validatingAttributesTimeout = null;
54
+ }
55
+
56
+ connectedCallback() {
57
+ super.connectedCallback();
58
+ this._resizeObserver.observe(this);
59
+ }
60
+
61
+ disconnectedCallback() {
62
+ super.disconnectedCallback();
63
+ this._resizeObserver.disconnect();
64
+ }
65
+
66
+ firstUpdated(changedProperties) {
67
+ super.firstUpdated(changedProperties);
68
+ this._validateAttributes();
69
+ }
70
+
71
+ async getIllustration(illustrationName) {
72
+ if (!illustrationName) return;
73
+
74
+ const svg = await loadSvg(illustrationName);
75
+ if (!svg) setTimeout(() => {
76
+ throw new Error(`<d2l-empty-state-illustrated-${this._illustratedComponentType}>: Unable to retrieve requested illustration.`);
77
+ });
78
+ return svg ? html`${unsafeSVG(svg.val)}` : nothing;
79
+ }
80
+
81
+ getIllustrationContainerStyle() {
82
+ return {
83
+ height: `${this._contentHeight}px`,
84
+ };
85
+ }
86
+
87
+ getTitleClass() {
88
+ return {
89
+ 'd2l-empty-state-title': true,
90
+ 'd2l-empty-state-title-small': this._titleSmall,
91
+ 'd2l-empty-state-title-large': !this._titleSmall,
92
+ };
93
+ }
94
+
95
+ _onResize(entries) {
96
+ if (!entries || entries.length === 0) return;
97
+ const entry = entries[0];
98
+ this._contentHeight = Math.min(entry.contentRect.right / illustrationAspectRatio, 330);
99
+ this._titleSmall = entry.contentRect.right <= 615;
100
+ }
101
+
102
+ _validateAttributes() {
103
+ clearTimeout(this._validatingAttributesTimeout);
104
+ // don't error immediately in case it doesn't get set immediately
105
+ this._validatingAttributesTimeout = setTimeout(() => {
106
+ this._validatingAttributesTimeout = null;
107
+ const hasTitleText = (typeof this.titleText === 'string') && this.titleText.length > 0;
108
+ const hasDescription = (typeof this.description === 'string') && this.description.length > 0;
109
+
110
+ if (!hasTitleText && !this._missingTitleTextErrorHasBeenThrown) {
111
+ this._missingTitleTextErrorHasBeenThrown = true;
112
+ setTimeout(() => {
113
+ throw new Error(`<d2l-empty-state-illustrated-${this._illustratedComponentType}>: missing required "titleText" attribute.`);
114
+ });
115
+ }
116
+
117
+ if (!hasDescription && !this._missingDescriptionErrorHasBeenThrown) {
118
+ this._missingDescriptionErrorHasBeenThrown = true;
119
+ setTimeout(() => {
120
+ throw new Error(`<d2l-empty-state-illustrated-${this._illustratedComponentType}>: missing required "description" attribute.`);
121
+ });
122
+ }
123
+ }, 3000);
124
+ }
125
+
126
+ };
@@ -0,0 +1,82 @@
1
+ import '../button/button-subtle.js';
2
+ import { emptyStateSimpleStyles, emptyStateStyles } from './empty-state-styles.js';
3
+ import { html, LitElement, nothing } from 'lit';
4
+ import { bodyCompactStyles } from '../typography/styles.js';
5
+ import { RtlMixin } from '../../mixins/rtl-mixin.js';
6
+
7
+ /**
8
+ * The `d2l-empty-state-simple-button` component is an empty state component that displays a description and action button.
9
+ * @fires d2l-empty-state-action - Dispatched when the action button is clicked
10
+ */
11
+ class EmptyStateSimpleButton extends RtlMixin(LitElement) {
12
+
13
+ static get properties() {
14
+ return {
15
+ /**
16
+ * The action text to be used in the subtle button
17
+ * @type {string}
18
+ */
19
+ actionText: { type: String, attribute: 'action-text' },
20
+ /**
21
+ * REQUIRED: A description giving details about the empty state
22
+ * @type {string}
23
+ */
24
+ description: { type: String },
25
+ };
26
+ }
27
+
28
+ static get styles() {
29
+ return [bodyCompactStyles, emptyStateStyles, emptyStateSimpleStyles];
30
+ }
31
+
32
+ constructor() {
33
+ super();
34
+ this._missingDescriptionErrorHasBeenThrown = false;
35
+ this._validatingDescriptionTimeout = null;
36
+ }
37
+
38
+ firstUpdated(changedProperties) {
39
+ super.firstUpdated(changedProperties);
40
+ this._validateDescription();
41
+ }
42
+
43
+ render() {
44
+ const actionButton = this.actionText
45
+ ? html`
46
+ <d2l-button-subtle
47
+ class="d2l-empty-state-action"
48
+ @click=${this._handleActionClick}
49
+ h-align="text"
50
+ text=${this.actionText}
51
+ slim>
52
+ </d2l-button-subtle>`
53
+ : nothing;
54
+
55
+ return html`
56
+ <p class="d2l-body-compact d2l-empty-state-description">${this.description}</p>
57
+ ${actionButton}
58
+ `;
59
+ }
60
+
61
+ _handleActionClick(e) {
62
+ e.stopPropagation();
63
+ this.dispatchEvent(new CustomEvent('d2l-empty-state-action'));
64
+ }
65
+
66
+ _validateDescription() {
67
+ clearTimeout(this._validatingDescriptionTimeout);
68
+ // don't error immediately in case it doesn't get set immediately
69
+ this._validatingDescriptionTimeout = setTimeout(() => {
70
+ this._validatingDescriptionTimeout = null;
71
+ const hasDescription = (typeof this.description === 'string') && this.description.length > 0;
72
+
73
+ if (!hasDescription && !this._missingDescriptionErrorHasBeenThrown) {
74
+ this._missingDescriptionErrorHasBeenThrown = true;
75
+ setTimeout(() => { throw new Error('<d2l-empty-state-simple-button>: missing required "description" attribute.'); });
76
+ }
77
+ }, 3000);
78
+ }
79
+
80
+ }
81
+
82
+ customElements.define('d2l-empty-state-simple-button', EmptyStateSimpleButton);
@@ -0,0 +1,74 @@
1
+ import { emptyStateSimpleStyles, emptyStateStyles } from './empty-state-styles.js';
2
+ import { html, LitElement, nothing } from 'lit';
3
+ import { bodyCompactStyles } from '../typography/styles.js';
4
+ import { linkStyles } from '../link/link.js';
5
+ import { RtlMixin } from '../../mixins/rtl-mixin.js';
6
+
7
+ /**
8
+ * The `d2l-empty-state-simple-link` component is an empty state component that displays a description and action link.
9
+ */
10
+ class EmptyStateSimpleLink extends RtlMixin(LitElement) {
11
+
12
+ static get properties() {
13
+ return {
14
+ /**
15
+ * The action URL or URL fragment of the link
16
+ * @type {string}
17
+ */
18
+ actionHref: { type: String, attribute: 'action-href' },
19
+ /**
20
+ * The action text to be used in the link
21
+ * @type {string}
22
+ */
23
+ actionText: { type: String, attribute: 'action-text' },
24
+ /**
25
+ * REQUIRED: A description giving details about the empty state
26
+ * @type {string}
27
+ */
28
+ description: { type: String }
29
+ };
30
+ }
31
+
32
+ static get styles() {
33
+ return [bodyCompactStyles, emptyStateStyles, emptyStateSimpleStyles, linkStyles];
34
+ }
35
+
36
+ constructor() {
37
+ super();
38
+ this._missingDescriptionErrorHasBeenThrown = false;
39
+ this._validatingDescriptionTimeout = null;
40
+ }
41
+
42
+ firstUpdated(changedProperties) {
43
+ super.firstUpdated(changedProperties);
44
+ this._validateDescription();
45
+ }
46
+
47
+ render() {
48
+ const actionLink = this.actionText && this.actionHref
49
+ ? html`<a class="d2l-body-compact d2l-link" href=${this.actionHref}>${this.actionText}</a>`
50
+ : nothing;
51
+
52
+ return html`
53
+ <p class="d2l-body-compact d2l-empty-state-description">${this.description}</p>
54
+ ${actionLink}
55
+ `;
56
+ }
57
+
58
+ _validateDescription() {
59
+ clearTimeout(this._validatingDescriptionTimeout);
60
+ // don't error immediately in case it doesn't get set immediately
61
+ this._validatingDescriptionTimeout = setTimeout(() => {
62
+ this._validatingDescriptionTimeout = null;
63
+ const hasDescription = (typeof this.description === 'string') && this.description.length > 0;
64
+
65
+ if (!hasDescription && !this._missingDescriptionErrorHasBeenThrown) {
66
+ this._missingDescriptionErrorHasBeenThrown = true;
67
+ setTimeout(() => { throw new Error('<d2l-empty-state-simple-link>: missing required "description" attribute.'); });
68
+ }
69
+ }, 3000);
70
+ }
71
+
72
+ }
73
+
74
+ customElements.define('d2l-empty-state-simple-link', EmptyStateSimpleLink);
@@ -0,0 +1,84 @@
1
+ import '../colors/colors.js';
2
+ import { css } from 'lit';
3
+
4
+ export const emptyStateStyles = css`
5
+
6
+ :host {
7
+ border: 1px solid var(--d2l-color-mica);
8
+ border-radius: 0.3rem;
9
+ display: block;
10
+ padding: 1.2rem 1.5rem;
11
+ }
12
+
13
+ :host([hidden]) {
14
+ display: none;
15
+ }
16
+
17
+ `;
18
+
19
+ export const emptyStateSimpleStyles = css`
20
+
21
+ :host([dir="rtl"]) .d2l-empty-state-description {
22
+ padding-left: 0.5rem;
23
+ padding-right: 0;
24
+ }
25
+
26
+ .d2l-empty-state-description {
27
+ display: inline;
28
+ padding-right: 0.5rem;
29
+ }
30
+
31
+ .d2l-empty-state-action {
32
+ vertical-align: top;
33
+ }
34
+
35
+ `;
36
+
37
+ export const emptyStateIllustratedStyles = css`
38
+
39
+ :host {
40
+ text-align: center;
41
+ }
42
+
43
+ .d2l-empty-state-action {
44
+ margin-top: 0.5rem;
45
+ }
46
+
47
+ .d2l-empty-state-description {
48
+ margin: 0 auto 0.3rem;
49
+ max-width: 500px;
50
+ width: 100%;
51
+ }
52
+
53
+ .d2l-empty-state-title {
54
+ margin-bottom: 0.9rem;
55
+ }
56
+
57
+ .d2l-empty-state-title-large {
58
+ font-size: 1.5rem;
59
+ line-height: 1.8rem;
60
+ margin: 1rem 0 1.5rem 0;
61
+ }
62
+
63
+ .d2l-empty-state-title-small {
64
+ font-size: 1rem;
65
+ font-weight: 700;
66
+ line-height: 1.5rem;
67
+ margin-top: 0.5rem;
68
+ }
69
+
70
+ ::slotted(*) {
71
+ display: none;
72
+ }
73
+
74
+ ::slotted(svg:first-child) {
75
+ display: inline-block;
76
+ }
77
+
78
+ svg {
79
+ height: 100%;
80
+ max-width: 500px;
81
+ width: 100%;
82
+ }
83
+
84
+ `;