@brightspace-ui/core 3.227.14 → 3.227.16

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.
@@ -1,7 +1,7 @@
1
1
  import '../colors/colors.js';
2
2
  import '../loading-spinner/loading-spinner.js';
3
3
  import { css, html, LitElement, nothing } from 'lit';
4
- import { getOffsetParent } from '../../helpers/dom.js';
4
+ import { getComposedChildren, getComposedParent } from '../../helpers/dom.js';
5
5
  import { styleMap } from 'lit/directives/style-map.js';
6
6
 
7
7
  const BACKDROP_DELAY_MS = 800;
@@ -25,6 +25,11 @@ class LoadingBackdrop extends LitElement {
25
25
  * @type {boolean}
26
26
  */
27
27
  shown: { type: Boolean },
28
+ /**
29
+ * Used to identify content that the backdrop should make inert
30
+ * @type {boolean}
31
+ */
32
+ for: { type: String },
28
33
  _state: { type: String, reflect: true },
29
34
  _spinnerTop: { state: true }
30
35
  };
@@ -156,6 +161,19 @@ class LoadingBackdrop extends LitElement {
156
161
  this._state = 'hiding';
157
162
  }
158
163
  }
164
+ #getBackdropTarget() {
165
+ const parent = getComposedParent(this);
166
+
167
+ if (!this.for) { return parent; }
168
+
169
+ const targetedChildren = getComposedChildren(
170
+ parent,
171
+ (elem) => elem.id === this.for,
172
+ false
173
+ );
174
+
175
+ return targetedChildren.length === 0 ? parent : targetedChildren[0];
176
+ }
159
177
  #handleTransitionEnd() {
160
178
  if (this._state === 'hiding') {
161
179
  this.#hide();
@@ -164,14 +182,14 @@ class LoadingBackdrop extends LitElement {
164
182
  #hide() {
165
183
  this._state = 'hidden';
166
184
 
167
- const containingBlock = getOffsetParent(this);
185
+ const containingBlock = this.#getBackdropTarget();
168
186
 
169
187
  if (containingBlock.dataset.initiallyInert !== '1') containingBlock.removeAttribute('inert');
170
188
  }
171
189
  #show() {
172
190
  this._state = reduceMotion ? 'shown' : 'showing';
173
191
 
174
- const containingBlock = getOffsetParent(this);
192
+ const containingBlock = this.#getBackdropTarget();
175
193
 
176
194
  if (containingBlock.getAttribute('inert') !== null) containingBlock.dataset.initiallyInert = '1';
177
195
 
@@ -29,7 +29,7 @@ class CollapsiblePanelSummaryItem extends SkeletonMixin(LitElement) {
29
29
  static get styles() {
30
30
  return [super.styles, bodySmallStyles, css`
31
31
  :host {
32
- color: var(--d2l-color-galena);
32
+ color: var(--d2l-theme-text-color-static-faint);
33
33
  display: block;
34
34
  }
35
35
  :host([hidden]) {
@@ -111,7 +111,7 @@ class CollapsiblePanel extends SkeletonMixin(FocusMixin(LitElement)) {
111
111
  static get styles() {
112
112
  return [super.styles, heading1Styles, heading2Styles, heading3Styles, heading4Styles, css`
113
113
  :host {
114
- --d2l-collapsible-panel-focus-outline: solid 2px var(--d2l-color-celestine);
114
+ --d2l-collapsible-panel-focus-outline: solid 2px var(--d2l-theme-border-color-focus);
115
115
  --d2l-collapsible-panel-spacing-inline: 0.9rem;
116
116
  --d2l-collapsible-panel-header-spacing: 0.6rem;
117
117
  --d2l-collapsible-panel-transition-time: 0.2s;
@@ -125,16 +125,16 @@ class CollapsiblePanel extends SkeletonMixin(FocusMixin(LitElement)) {
125
125
  --d2l-collapsible-panel-spacing-inline: 2rem;
126
126
  }
127
127
  .d2l-collapsible-panel {
128
- border: 1px solid var(--d2l-color-mica);
128
+ border: 1px solid var(--d2l-theme-border-color-standard);
129
129
  border-radius: 0.4rem;
130
130
  }
131
131
  :host(:not([expanded]):not([skeleton])) .d2l-collapsible-panel {
132
132
  cursor: pointer;
133
133
  }
134
134
  :host([type="subtle"]) .d2l-collapsible-panel {
135
- background-color: white;
135
+ background-color: var(--d2l-theme-background-color-base);
136
136
  border: none;
137
- box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.03);
137
+ box-shadow: var(--d2l-theme-shadow-attached);
138
138
  }
139
139
  :host([type="inline"]) .d2l-collapsible-panel {
140
140
  border-left: none;
@@ -174,7 +174,7 @@ class CollapsiblePanel extends SkeletonMixin(FocusMixin(LitElement)) {
174
174
  outline-offset: -2px;
175
175
  }
176
176
  .d2l-collapsible-panel.scrolled .d2l-collapsible-panel-header {
177
- background-color: white;
177
+ background-color: var(--d2l-theme-background-color-base);
178
178
  box-shadow: 0 8px 12px -9px rgba(0, 0, 0, 0.3);
179
179
  position: sticky;
180
180
  top: 0;
@@ -234,7 +234,7 @@ class CollapsiblePanel extends SkeletonMixin(FocusMixin(LitElement)) {
234
234
  gap: 0.3rem;
235
235
  }
236
236
  .d2l-collapsible-panel-header-actions::after {
237
- border-inline-end: 1px solid var(--d2l-color-mica);
237
+ border-inline-end: 1px solid var(--d2l-theme-border-color-standard);
238
238
  content: "";
239
239
  display: flex;
240
240
  margin: 0.3rem;
@@ -300,7 +300,7 @@ class CollapsiblePanel extends SkeletonMixin(FocusMixin(LitElement)) {
300
300
  /* stylelint-enable */
301
301
  }
302
302
  .d2l-collapsible-panel-divider {
303
- border-bottom: 1px solid var(--d2l-color-mica);
303
+ border-bottom: 1px solid var(--d2l-theme-border-color-standard);
304
304
  margin-inline: var(--d2l-collapsible-panel-spacing-inline);
305
305
  opacity: 1;
306
306
  }
@@ -0,0 +1,142 @@
1
+ import '../../colors/colors.js';
2
+ import { css, html, LitElement } from 'lit';
3
+ import { descriptionListStyles } from '../description-list-wrapper.js';
4
+ import { ifDefined } from 'lit/directives/if-defined.js';
5
+
6
+ class TestDescriptionList extends LitElement {
7
+ static get properties() {
8
+ return {
9
+ /**
10
+ * Width for component to use a stacked layout
11
+ * @type {number}
12
+ */
13
+ breakpoint: { type: Number, reflect: true },
14
+ /**
15
+ * Force the component to always use a stacked layout; will override breakpoint attribute
16
+ * @type {boolean}
17
+ */
18
+ forceStacked: { type: Boolean, reflect: true, attribute: 'force-stacked' },
19
+ /**
20
+ * @ignore
21
+ */
22
+ type: { type: String, reflect: true },
23
+ };
24
+ }
25
+
26
+ static get styles() {
27
+ return [descriptionListStyles, css`
28
+ .user {
29
+ align-items: center;
30
+ display: flex;
31
+ gap: 0.5rem;
32
+ }
33
+ .avatar {
34
+ align-items: center;
35
+ background-color: var(--d2l-color-cinnabar-minus-1);
36
+ border-radius: 0.25rem;
37
+ color: white;
38
+ display: flex;
39
+ font-size: 0.7rem;
40
+ font-weight: 700;
41
+ height: 1.5rem;
42
+ justify-content: center;
43
+ width: 1.5rem;
44
+ }
45
+ `];
46
+ }
47
+
48
+ constructor() {
49
+ super();
50
+ this.type = 'default';
51
+ }
52
+
53
+ render() {
54
+ return html`
55
+ <d2l-dl-wrapper
56
+ breakpoint="${ifDefined(this.breakpoint)}"
57
+ ?force-stacked="${this.forceStacked}"
58
+ >
59
+ ${this._renderExample()}
60
+ </d2l-dl-wrapper>
61
+ `;
62
+ }
63
+
64
+ _renderExample() {
65
+ if (this.type === 'default') {
66
+ return html`
67
+ <dl>
68
+ <dt>Course Name</dt>
69
+ <dd>Brightspace 101B</dd>
70
+
71
+ <dt>Course Code</dt>
72
+ <dd>BSPC 101B</dd>
73
+
74
+ <dt>Start Date</dt>
75
+ <dd>June 14 2022</dd>
76
+
77
+ <dt>Semester</dt>
78
+ <dd>2022 Summer</dd>
79
+ </dl>
80
+ `;
81
+ }
82
+
83
+ if (this.type === 'long') {
84
+ return html`
85
+ <dl>
86
+ <dt>Course Code That Represents The Course as a Short String</dt>
87
+ <dd>A short string that represents the course, often with important information such as section or room number.</dd>
88
+
89
+ <dt>Availability Dates</dt>
90
+ <dd>The start and end date for the course. Learners can't access courses outside these dates.</dd>
91
+ </dl>
92
+ `;
93
+ }
94
+
95
+ if (this.type === 'activity-display') {
96
+ return html`
97
+ <dl>
98
+ <dt>Submission type</dt>
99
+ <dd>File submission</dd>
100
+
101
+ <dt>Files allowed per submission</dt>
102
+ <dd>Unlimited</dd>
103
+
104
+ <dt>File extension</dt>
105
+ <dd>PDF</dd>
106
+
107
+ <dt>Allowed Submissions</dt>
108
+ <dd>Only one submission allowed</dd>
109
+ </dl>
110
+ `;
111
+ }
112
+
113
+ if (this.type === 'bulk-course-import') {
114
+ return html`
115
+ <dl>
116
+ <dt>Course code</dt>
117
+ <dd>fd6b9fd8-29bd-44ef-8322-d6b379b71411</dd>
118
+
119
+ <dt>Course name</dt>
120
+ <dd>Telkom MOMP Course 1</dd>
121
+
122
+ <dt>Course ID</dt>
123
+ <dd>250003</dd>
124
+ </dl>
125
+ `;
126
+ }
127
+
128
+ if (this.type === 'slotted') {
129
+ return html`
130
+ <dl style="align-items: center">
131
+ <dt>User</dt>
132
+ <dd><div class="user"><div class="avatar">JS</div>John Smith</div></dd>
133
+
134
+ <dt>Submitted</dt>
135
+ <dd>Dec 30, 2021 5:34 PM</dd>
136
+ </dl>
137
+ `;
138
+ }
139
+ }
140
+ }
141
+
142
+ customElements.define('d2l-test-dl', TestDescriptionList);
@@ -0,0 +1,48 @@
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
+
10
+ import './description-list-test.js';
11
+ </script>
12
+ </head>
13
+ <body unresolved>
14
+ <d2l-demo-page page-title="d2l-description-list">
15
+
16
+ <h2>Short</h2>
17
+ <d2l-demo-snippet full-width>
18
+ <d2l-test-dl></d2l-test-dl>
19
+ </d2l-demo-snippet>
20
+
21
+ <h2>Long</h2>
22
+ <d2l-demo-snippet full-width>
23
+ <d2l-test-dl type="long" breakpoint="300"></d2l-test-dl>
24
+ </d2l-demo-snippet>
25
+
26
+ <h2>Stacked</h2>
27
+ <d2l-demo-snippet fullscreen>
28
+ <d2l-test-dl type="long" force-stacked></d2l-test-dl>
29
+ </d2l-demo-snippet>
30
+
31
+ <h2>Activity Display</h2>
32
+ <d2l-demo-snippet full-width>
33
+ <d2l-test-dl type="activity-display"></d2l-test-dl>
34
+ </d2l-demo-snippet>
35
+
36
+ <h2>Bulk Course Import</h2>
37
+ <d2l-demo-snippet full-width>
38
+ <d2l-test-dl type="bulk-course-import"></d2l-test-dl>
39
+ </d2l-demo-snippet>
40
+
41
+ <h2>Slotted content</h2>
42
+ <d2l-demo-snippet full-width>
43
+ <d2l-test-dl type="slotted"></d2l-test-dl>
44
+ </d2l-demo-snippet>
45
+
46
+ </d2l-demo-page>
47
+ </body>
48
+ </html>
@@ -164,7 +164,6 @@ export const ListItemCheckboxMixin = superclass => class extends SkeletonMixin(s
164
164
  }
165
165
 
166
166
  _renderCheckbox() {
167
- /* eslint-disable lit/no-private-properties */
168
167
  return this.selectable ? html`
169
168
  <d2l-selection-input
170
169
  @d2l-selection-change="${this._onCheckboxChange}"
@@ -181,7 +180,6 @@ export const ListItemCheckboxMixin = superclass => class extends SkeletonMixin(s
181
180
  ?skeleton="${this.skeleton}">
182
181
  </d2l-selection-input>
183
182
  ` : nothing;
184
- /* eslint-enable */
185
183
  }
186
184
 
187
185
  _renderCheckboxAction(inner) {
@@ -0,0 +1,35 @@
1
+ import { css, html, LitElement } from 'lit';
2
+ import { PageableMixin } from '../../paging/pageable-mixin.js';
3
+ import { SelectionMixin } from '../selection-mixin.js';
4
+
5
+ class DemoBase extends LitElement {
6
+ static get styles() {
7
+ return css`
8
+ :host {
9
+ display: block;
10
+ }
11
+ `;
12
+ }
13
+ render() {
14
+ return html`
15
+ <slot></slot>
16
+ `;
17
+ }
18
+ }
19
+
20
+ class DemoSelection extends SelectionMixin(DemoBase) {}
21
+
22
+ class DemoPageable extends PageableMixin(DemoBase) {
23
+ _getItemByIndex() {
24
+ return null;
25
+ }
26
+ _getItemShowingCount() {
27
+ return 3;
28
+ }
29
+ }
30
+
31
+ class DemoSelectionPageable extends SelectionMixin(DemoPageable) {}
32
+
33
+ customElements.define('d2l-demo-selection', DemoSelection);
34
+ customElements.define('d2l-demo-pageable', DemoPageable);
35
+ customElements.define('d2l-demo-selection-pageable', DemoSelectionPageable);
@@ -0,0 +1,198 @@
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 '../../dropdown/dropdown-menu.js';
10
+ import '../../menu/menu.js';
11
+ import '../../paging/pager-load-more.js';
12
+ import '../selection-action.js';
13
+ import '../selection-action-dropdown.js';
14
+ import '../selection-action-menu-item.js';
15
+ import '../selection-controls.js';
16
+ import '../selection-input.js';
17
+ import '../selection-select-all.js';
18
+ import '../selection-summary.js';
19
+ import './demo-selection.js';
20
+ </script>
21
+ <style>
22
+ ul {
23
+ padding: 0;
24
+ }
25
+ li {
26
+ list-style-type: none;
27
+ }
28
+ d2l-selection-input {
29
+ margin-right: 10px;
30
+ }
31
+ [dir="rtl"] d2l-selection-input {
32
+ margin-left: 10px;
33
+ margin-right: 0;
34
+ }
35
+ .d2l-selection-collections {
36
+ display: flex;
37
+ flex-direction: row;
38
+ justify-content: space-between;
39
+ }
40
+ .d2l-selection-collection {
41
+ display: flex;
42
+ flex-basis: 45%;
43
+ flex-direction: column;
44
+ }
45
+ </style>
46
+ </head>
47
+ <body unresolved>
48
+
49
+ <d2l-demo-page page-title="Selection Components">
50
+
51
+ <h2>Multiple Selection</h2>
52
+
53
+ <d2l-demo-snippet>
54
+ <template>
55
+ <d2l-demo-selection>
56
+ <d2l-selection-controls>
57
+ <d2l-selection-action text="Bookmark" icon="tier1:bookmark-hollow" max-selection-count="2" requires-selection></d2l-selection-action>
58
+ <d2l-selection-action text="Settings" icon="tier1:gear"></d2l-selection-action>
59
+ <d2l-selection-action-dropdown text="Actions 1" requires-selection>
60
+ <d2l-dropdown-menu>
61
+ <d2l-menu label="Actions">
62
+ <d2l-selection-action-menu-item text="Action 1"></d2l-selection-action-menu-item>
63
+ <d2l-selection-action-menu-item text="Action 2"></d2l-selection-action-menu-item>
64
+ </d2l-menu>
65
+ </d2l-dropdown-menu>
66
+ </d2l-selection-action-dropdown>
67
+ </d2l-selection-controls>
68
+
69
+ <ul>
70
+ <li><d2l-selection-input key="geo" label="Geography" selected></d2l-selection-input>Geography</li>
71
+ <li><d2l-selection-input key="sci" label="Science"></d2l-selection-input>Science</li>
72
+ <li><d2l-selection-input key="mth" label="Math"></d2l-selection-input>Math</li>
73
+ </ul>
74
+ </d2l-demo-selection>
75
+ </template>
76
+ </d2l-demo-snippet>
77
+
78
+ <h2>Single Selection</h2>
79
+
80
+ <d2l-demo-snippet>
81
+ <template>
82
+ <d2l-demo-selection selection-single>
83
+ <d2l-selection-controls>
84
+ <d2l-selection-action text="Bookmark" icon="tier1:bookmark-hollow" requires-selection></d2l-selection-action>
85
+ <d2l-selection-action text="Settings" icon="tier1:gear"></d2l-selection-action>
86
+ </d2l-selection-controls>
87
+
88
+ <ul>
89
+ <li><d2l-selection-input key="geo" label="Geography"></d2l-selection-input>Geography</li>
90
+ <li><d2l-selection-input key="sci" label="Science"></d2l-selection-input>Science</li>
91
+ <li><d2l-selection-input key="mth" label="Math"></d2l-selection-input>Math</li>
92
+ </ul>
93
+ </d2l-demo-selection>
94
+ </template>
95
+ </d2l-demo-snippet>
96
+
97
+ <h2>Selection controls with pageable + selection</h2>
98
+
99
+ <d2l-demo-snippet>
100
+ <template>
101
+ <d2l-demo-selection-pageable item-count="5">
102
+ <d2l-selection-controls select-all-pages-allowed>
103
+ <d2l-selection-action text="Bookmark" icon="tier1:bookmark-hollow" max-selection-count="4" requires-selection></d2l-selection-action>
104
+ <d2l-selection-action text="Settings" icon="tier1:gear"></d2l-selection-action>
105
+ </d2l-selection-controls>
106
+
107
+ <ul>
108
+ <li><d2l-selection-input key="geo" label="Geography"></d2l-selection-input>Geography</li>
109
+ <li><d2l-selection-input key="sci" label="Science"></d2l-selection-input>Science</li>
110
+ <li><d2l-selection-input key="mth" label="Math"></d2l-selection-input>Math</li>
111
+ </ul>
112
+ <d2l-pager-load-more has-more page-size="1"></d2l-pager-load-more>
113
+ </d2l-demo-selection-pageable>
114
+ </template>
115
+ </d2l-demo-snippet>
116
+
117
+ <h2>Selection controls with pageable (no selection)</h2>
118
+
119
+ <d2l-demo-snippet>
120
+ <template>
121
+ <d2l-demo-pageable item-count="5">
122
+ <d2l-selection-controls>
123
+ <d2l-selection-action text="Bookmark" icon="tier1:bookmark-hollow" requires-selection></d2l-selection-action>
124
+ <d2l-selection-action text="Settings" icon="tier1:gear"></d2l-selection-action>
125
+ </d2l-selection-controls>
126
+
127
+ <ul>
128
+ <li><d2l-selection-input key="geo" label="Geography"></d2l-selection-input>Geography</li>
129
+ <li><d2l-selection-input key="sci" label="Science"></d2l-selection-input>Science</li>
130
+ <li><d2l-selection-input key="mth" label="Math"></d2l-selection-input>Math</li>
131
+ </ul>
132
+ <d2l-pager-load-more has-more page-size="1"></d2l-pager-load-more>
133
+ </d2l-demo-pageable>
134
+ </template>
135
+ </d2l-demo-snippet>
136
+
137
+ <h2>No-sticky selection controls</h2>
138
+
139
+ <d2l-demo-snippet>
140
+ <template>
141
+ <d2l-demo-selection>
142
+ <d2l-selection-controls no-sticky>
143
+ <d2l-selection-action text="Bookmark" icon="tier1:bookmark-hollow" requires-selection></d2l-selection-action>
144
+ <d2l-selection-action text="Settings" icon="tier1:gear"></d2l-selection-action>
145
+ </d2l-selection-controls>
146
+
147
+ <ul>
148
+ <li><d2l-selection-input key="geo" label="Geography"></d2l-selection-input>Geography</li>
149
+ <li><d2l-selection-input key="sci" label="Science"></d2l-selection-input>Science</li>
150
+ <li><d2l-selection-input key="mth" label="Math"></d2l-selection-input>Math</li>
151
+ </ul>
152
+ </d2l-demo-selection>
153
+ </template>
154
+ </d2l-demo-snippet>
155
+
156
+ <h2>Selection Components Outside of Collection</h2>
157
+
158
+ <d2l-demo-snippet>
159
+ <template>
160
+ <div class="d2l-selection-collections">
161
+ <div class="d2l-selection-collection">
162
+ Pick Your Toppings
163
+ <d2l-selection-controls selection-for="collection-1" pageable-for="collection-1" select-all-pages-allowed>
164
+ <d2l-selection-action selection-for="collection-1" text="Add Note" icon="tier1:add-message"></d2l-selection-action>
165
+ </d2l-selection-controls>
166
+
167
+ <d2l-demo-selection-pageable id="collection-1" item-count="5">
168
+ <ul>
169
+ <li><d2l-selection-input key="let" label="Lettuce" selected></d2l-selection-input>Lettuce</li>
170
+ <li><d2l-selection-input key="tom" label="Tomato"></d2l-selection-input>Tomato</li>
171
+ <li><d2l-selection-input key="onion" label="Onion"></d2l-selection-input>Onion</li>
172
+ </ul>
173
+ </d2l-demo-selection-pageable>
174
+ <d2l-pager-load-more has-more page-size="1" pageable-for="collection-1"></d2l-pager-load-more>
175
+ <d2l-selection-action selection-for="collection-1" text="Save" requires-selection></d2l-selection-action>
176
+ </div>
177
+
178
+ <div class="d2l-selection-collection">
179
+ Pick Your Bread
180
+ <d2l-selection-controls selection-for="collection-2">
181
+ <d2l-selection-action selection-for="collection-2" text="Add Note" icon="tier1:add-message"></d2l-selection-action>
182
+ </d2l-selection-controls>
183
+ <d2l-demo-selection id="collection-2" selection-single>
184
+ <ul>
185
+ <li><d2l-selection-input key="it" label="Italian"></d2l-selection-input>Italian</li>
186
+ <li><d2l-selection-input key="ww" label="Whole Wheat"></d2l-selection-input>Whole Wheat</li>
187
+ <li><d2l-selection-input key="herb" label="Herb and Garlic"></d2l-selection-input>Herb and Garlic</li>
188
+ </ul>
189
+ </d2l-demo-selection>
190
+ <d2l-selection-action selection-for="collection-2" text="Save" requires-selection></d2l-selection-action>
191
+ </div>
192
+ </div>
193
+ </template>
194
+ </d2l-demo-snippet>
195
+
196
+ </d2l-demo-page>
197
+ </body>
198
+ </html>
@@ -0,0 +1,271 @@
1
+ import '../table-col-sort-button.js';
2
+ import '../table-col-sort-button-item.js';
3
+ import '../table-controls.js';
4
+ import '../../button/button-icon.js';
5
+ import '../../dropdown/dropdown-button-subtle.js';
6
+ import '../../dropdown/dropdown-context-menu.js';
7
+ import '../../dropdown/dropdown-menu.js';
8
+ import '../../inputs/input-checkbox.js';
9
+ import '../../inputs/input-text.js';
10
+ import '../../menu/menu.js';
11
+ import '../../menu/menu-item.js';
12
+ import '../../paging/pager-load-more.js';
13
+ import '../../selection/selection-action.js';
14
+ import '../../selection/selection-action-dropdown.js';
15
+ import '../../selection/selection-action-menu-item.js';
16
+ import '../../selection/selection-input.js';
17
+
18
+ import { css, html, nothing } from 'lit';
19
+ import { tableStyles, TableWrapper } from '../table-wrapper.js';
20
+ import { DemoPassthroughMixin } from '../../demo/demo-passthrough-mixin.js';
21
+ import { ifDefined } from 'lit/directives/if-defined.js';
22
+
23
+ const columns = ['Population', 'Size', 'Elevation'];
24
+ const thText = ['Additional', 'Placeholder', 'Header', 'Row', 'Cells'];
25
+
26
+ const data = () => [
27
+ { name: 'Ottawa, Canada', data: { 'city': 'Ottawa', 'country': 'Canada', 'population': 994837, 'size': 2790, 'elevation': 70, 'latitude': 45.32, 'longitude': -75.71 }, selected: true },
28
+ { name: 'Toronto, Canada', data: { 'city': 'Toronto', 'country': 'Canada', 'population': 2930000, 'size': 630, 'elevation': 76, 'latitude': 43.69, 'longitude': -79.41 }, selected: true },
29
+ { name: 'Sydney, Australia', data: { 'city': 'Sydney', 'country': 'Australia', 'population': 5312000, 'size': 12368, 'elevation': 3, 'latitude': -33.86, 'longitude': 151.13 }, selected: false },
30
+ { name: 'Cairo, Egypt', data: { 'city': 'Cairo', 'country': 'Egypt', 'population': 9540000, 'size': 3085, 'elevation': 23, 'latitude': 30.05, 'longitude': 31.25 }, selected: false },
31
+ { name: 'Moscow, Russia', data: { 'city': 'Moscow', 'country': 'Russia', 'population': 12712305, 'size': 2511, 'elevation': 124, 'latitude': 55.70, 'longitude': 35.59 }, selected: false },
32
+ { name: 'London, England', data: { 'city': 'London', 'country': 'England', 'population': 8982000, 'size': 1572, 'elevation': 11, 'latitude': 51.49, 'longitude': -0.12 }, selected: false },
33
+ { name: 'Tokyo, Japan', data: { 'city': 'Tokyo', 'country': 'Japan', 'population': 13960000, 'size': 2194, 'elevation': 40, 'latitude': 35.68, 'longitude': 139.74 }, selected: false }
34
+ ];
35
+
36
+ const formatter = new Intl.NumberFormat('en-US');
37
+
38
+ class TestTable extends DemoPassthroughMixin(TableWrapper, 'd2l-table-wrapper') {
39
+
40
+ static get properties() {
41
+ return {
42
+ paging: { type: Boolean, reflect: true },
43
+ multiLine: { type: Boolean, attribute: 'multi-line' },
44
+ resetOnSort: { type: Boolean, attribute: 'reset-on-sort' },
45
+ showButtons: { type: Boolean, attribute: 'show-buttons' },
46
+ stickyControls: { attribute: 'sticky-controls', type: Boolean, reflect: true },
47
+ visibleBackground: { attribute: 'visible-background', type: Boolean, reflect: true },
48
+ _data: { state: true },
49
+ _sortField: { state: true },
50
+ _sortDesc: { state: true }
51
+ };
52
+ }
53
+
54
+ static get styles() {
55
+ return [tableStyles, css`
56
+ :host {
57
+ display: block;
58
+ }
59
+ :host([visible-background]) {
60
+ --d2l-table-controls-background-color: #dddddd;
61
+ }
62
+ .d2l-table > * > tr > :has(d2l-button-icon),
63
+ .d2l-table > * > tr > :has(d2l-dropdown-context-menu) {
64
+ padding-block: 0;
65
+ }
66
+ .d2l-table > * > tr > :has(d2l-table-col-sort-button) d2l-button-icon,
67
+ .d2l-table > * > tr > :has(d2l-table-col-sort-button) d2l-dropdown-context-menu {
68
+ vertical-align: top;
69
+ }
70
+ `];
71
+ }
72
+
73
+ constructor() {
74
+ super();
75
+
76
+ this.multiLine = false;
77
+ this.paging = false;
78
+ this.showButtons = false;
79
+ this.stickyControls = false;
80
+ this.visibleBackground = false;
81
+ this._data = data();
82
+ this._sortField = undefined;
83
+ this._sortDesc = false;
84
+ }
85
+
86
+ render() {
87
+ return html`
88
+ <d2l-table-wrapper item-count="${ifDefined(this.paging ? 500 : undefined)}">
89
+ <d2l-table-controls slot="controls" ?no-sticky="${!this.stickyControls}" select-all-pages-allowed>
90
+ <d2l-selection-action
91
+ text="Sticky controls"
92
+ icon="tier1:${this.stickyControls ? 'check' : 'close-default'}"
93
+ @d2l-selection-action-click="${this._toggleStickyControls}"
94
+ ></d2l-selection-action>
95
+ <d2l-selection-action
96
+ text="Sticky headers"
97
+ icon="tier1:${this.stickyHeaders ? 'check' : 'close-default'}"
98
+ @d2l-selection-action-click="${this._toggleStickyHeaders}"
99
+ ></d2l-selection-action>
100
+ <d2l-selection-action
101
+ text="Loading"
102
+ icon="tier1:${this.loading ? 'check' : 'close-default'}"
103
+ @d2l-selection-action-click="${this._toggleLoading}"
104
+ ></d2l-selection-action>
105
+ </d2l-table-controls>
106
+
107
+ <table class="d2l-table">
108
+ <thead>
109
+ ${this.multiLine ? html`
110
+ <tr>
111
+ <td scope="col" sticky><d2l-selection-select-all></d2l-selection-select-all></td>
112
+ ${this._renderDoubleSortButton('City', 'Country')}
113
+ <th scope="col" colspan="${columns.length + 1}" sticky>
114
+ Metrics
115
+ </th>
116
+ </tr>
117
+ <tr>
118
+ <th scope="col" sticky></th>
119
+ ${columns.map(columnHeading => this._renderSortButton(columnHeading))}
120
+ ${this._renderMenuSortButton('Coordinates', ['Latitude', 'Longitude'])}
121
+ </tr>
122
+ ` : html`
123
+ <tr>
124
+ <td scope="col" sticky><d2l-selection-select-all></d2l-selection-select-all></td>
125
+ ${this._renderDoubleSortButton('City', 'Country')}
126
+ ${columns.map(columnHeading => this._renderSortButton(columnHeading))}
127
+ ${this._renderMenuSortButton('Coordinates', ['Latitude', 'Longitude'])}
128
+ </tr>
129
+ `}
130
+ </thead>
131
+ <tbody>
132
+ <tr class="d2l-table-header">
133
+ <th scope="col" sticky></th>
134
+ ${thText.map(text => html`<th scope="col">${text}</th>`)}
135
+ </tr>
136
+ <tr header>
137
+ <th scope="col" sticky></th>
138
+ ${thText.map(text => html`
139
+ <th scope="col">
140
+ ${text}${text === 'Placeholder' && this.showButtons ? html`<d2l-button-icon text="Help" icon="tier1:help"></d2l-button-icon>` : nothing}
141
+ </th>
142
+ `)}
143
+ </tr>
144
+ ${this._data.map(row => html`
145
+ <tr ?selected="${row.selected}" data-name="${row.name}">
146
+ <th scope="row" sticky>
147
+ <d2l-selection-input
148
+ @d2l-selection-change="${this._selectRow}"
149
+ ?selected="${row.selected}"
150
+ key="${row.name}"
151
+ label="${row.name}">
152
+ </d2l-selection-input>
153
+ </th>
154
+ <th scope="row">${row.name}</th>
155
+ ${columns.map(columnHeading => { const val = row.data[columnHeading.toLowerCase()]; return val ? html`<td>${formatter.format(val)}</td>` : null; }) }
156
+ <td>${[formatter.format(row.data.latitude), formatter.format(row.data.longitude)].join(', ')}</td>
157
+ </tr>
158
+ `)}
159
+ </tbody>
160
+ </table>
161
+ ${this.paging ? html`<d2l-pager-load-more slot="pager"
162
+ has-more
163
+ page-size="3"
164
+ @d2l-pager-load-more="${this._handlePagerLoadMore}"
165
+ ></d2l-pager-load-more>` : nothing}
166
+ </d2l-table-wrapper>
167
+ `;
168
+ }
169
+
170
+ async _handlePagerLoadMore(e) {
171
+ const pageSize = e.target.pageSize;
172
+ await new Promise(resolve => setTimeout(resolve, 1000));
173
+ const startIndex = this._data.length + 1;
174
+ for (let i = 0; i < pageSize; i++) {
175
+ this._data.push({ name: `City ${startIndex + i}, Country ${startIndex + i}`, data: { 'city': `City ${startIndex + i}`, 'country': `Country ${startIndex + i}`, 'population': 26320000, 'size': 6340, 'elevation': 4, 'latitude': 3, 'longitude': 3 }, selected: false });
176
+ }
177
+ this.requestUpdate();
178
+ e.detail.complete();
179
+ }
180
+
181
+ _handleSort(e) {
182
+ const field = e.target.innerText.toLowerCase();
183
+ const desc = e.target.hasAttribute('desc');
184
+ this._sortDesc = field === this._sortField ? !desc : false; // if sorting on same field then reverse, otherwise sort ascending
185
+ this._sortField = field;
186
+ this._handleSortData();
187
+ }
188
+
189
+ _handleSortComplex(e) {
190
+ this._sortField = e.target?.getAttribute('data-field');
191
+ this._sortDesc = e.target?.hasAttribute('data-desc');
192
+ this._handleSortData();
193
+ }
194
+
195
+ _handleSortData() {
196
+ this._data = (this.resetOnSort ? data() : this._data).sort((a, b) => {
197
+ if (this._sortDesc) {
198
+ if (a.data[this._sortField] > b.data[this._sortField]) return -1;
199
+ if (a.data[this._sortField] < b.data[this._sortField]) return 1;
200
+ } else {
201
+ if (a.data[this._sortField] < b.data[this._sortField]) return -1;
202
+ if (a.data[this._sortField] > b.data[this._sortField]) return 1;
203
+ }
204
+ return 0;
205
+ });
206
+ }
207
+
208
+ _renderDoubleSortButton(item1, item2) {
209
+ return html`
210
+ <th rowspan="${this.multiLine ? 2 : 1}" scope="col">
211
+ <d2l-table-col-sort-button
212
+ @click="${this._handleSort}"
213
+ ?desc="${this._sortDesc}"
214
+ ?nosort="${this._sortField !== item1.toLowerCase()}">${item1}</d2l-table-col-sort-button>
215
+ <d2l-table-col-sort-button
216
+ @click="${this._handleSort}"
217
+ ?desc="${this._sortDesc}"
218
+ ?nosort="${this._sortField !== item2.toLowerCase()}">${item2}</d2l-table-col-sort-button>
219
+ </th>
220
+ `;
221
+ }
222
+
223
+ _renderMenuSortButton(name, items) {
224
+ const noSort = !items.map(i => i.toLowerCase()).includes(this._sortField?.toLowerCase());
225
+ return html`
226
+ <th scope="col">
227
+ <d2l-table-col-sort-button
228
+ ?desc="${this._sortDesc}"
229
+ ?nosort="${noSort}">
230
+ <span>${name}</span>${items.map((item, idx) => html`
231
+ <d2l-table-col-sort-button-item slot="items" text="${item}, ascending" data-field="${item.toLowerCase()}" @d2l-table-col-sort-button-item-change="${this._handleSortComplex}" value="${idx * 2 + 1}"></d2l-table-col-sort-button-item>
232
+ <d2l-table-col-sort-button-item slot="items" text="${item}, descending" data-field="${item.toLowerCase()}" data-desc @d2l-table-col-sort-button-item-change="${this._handleSortComplex}" value="${idx * 2 + 2}"></d2l-table-col-sort-button-item>`)}
233
+ </d2l-table-col-sort-button>
234
+ </th>
235
+ `;
236
+ }
237
+
238
+ _renderSortButton(item) {
239
+ const noSort = this._sortField !== item.toLowerCase();
240
+ return html`
241
+ <th scope="col">
242
+ <d2l-table-col-sort-button
243
+ @click="${this._handleSort}"
244
+ source-type="numbers"
245
+ ?desc="${this._sortDesc}"
246
+ ?nosort="${noSort}">${item}</d2l-table-col-sort-button>
247
+ ${item === 'Size' && this.showButtons ? html`<d2l-dropdown-context-menu text="Help"></d2l-dropdown-context-menu>` : nothing}
248
+ </th>
249
+ `;
250
+ }
251
+
252
+ _selectRow(e) {
253
+ const country = e.target.parentNode.parentNode.dataset.name;
254
+ const row = this._data.find(row => row.name === country);
255
+ row.selected = e.target.selected;
256
+ this.requestUpdate();
257
+ }
258
+
259
+ _toggleLoading() {
260
+ this.loading = !this.loading;
261
+ }
262
+ _toggleStickyControls() {
263
+ this.stickyControls = !this.stickyControls;
264
+ }
265
+
266
+ _toggleStickyHeaders() {
267
+ this.stickyHeaders = !this.stickyHeaders;
268
+ }
269
+
270
+ }
271
+ customElements.define('d2l-test-table', TestTable);
@@ -0,0 +1,107 @@
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 './table-test.js';
10
+ </script>
11
+ </head>
12
+ <body unresolved>
13
+
14
+ <d2l-demo-page page-title="d2l-table">
15
+
16
+ <button id="print">Print</button>
17
+
18
+ <h2>Default</h2>
19
+ <d2l-demo-snippet>
20
+ <template>
21
+ <d2l-test-table type="default" sticky-controls show-buttons></d2l-test-table>
22
+ </template>
23
+ </d2l-demo-snippet>
24
+
25
+ <h2>Default, Sticky</h2>
26
+ <d2l-demo-snippet>
27
+ <template>
28
+ <d2l-test-table type="default" sticky-headers sticky-controls></d2l-test-table>
29
+ </template>
30
+ </d2l-demo-snippet>
31
+
32
+ <h2>Light</h2>
33
+ <d2l-demo-snippet>
34
+ <template>
35
+ <d2l-test-table type="light" sticky-controls show-buttons></d2l-test-table>
36
+ </template>
37
+ </d2l-demo-snippet>
38
+
39
+ <h2>Light, Sticky</h2>
40
+ <d2l-demo-snippet>
41
+ <template>
42
+ <d2l-test-table type="light" sticky-headers sticky-controls></d2l-test-table>
43
+ </template>
44
+ </d2l-demo-snippet>
45
+
46
+ <h2>Default, Paging</h2>
47
+ <d2l-demo-snippet>
48
+ <template>
49
+ <d2l-test-table type="default" sticky-controls paging></d2l-test-table>
50
+ </template>
51
+ </d2l-demo-snippet>
52
+
53
+ <h2>Default, Paging, Reset on sort</h2>
54
+ <d2l-demo-snippet>
55
+ <template>
56
+ <d2l-test-table type="default" sticky-controls paging reset-on-sort></d2l-test-table>
57
+ </template>
58
+ </d2l-demo-snippet>
59
+
60
+ <h2>Default, Visible controls background</h2>
61
+ <d2l-demo-snippet>
62
+ <template>
63
+ <d2l-test-table type="default" sticky-headers sticky-controls visible-background></d2l-test-table>
64
+ </template>
65
+ </d2l-demo-snippet>
66
+
67
+ <h2>Default, Sticky columns</h2>
68
+ <d2l-demo-snippet overflow-hidden>
69
+ <template>
70
+ <div style="overflow: auto; width: 400px;">
71
+ <d2l-test-table type="default" sticky-headers sticky-controls></d2l-test-table>
72
+ </div>
73
+ </template>
74
+ </d2l-demo-snippet>
75
+
76
+ <h2>Default with Scroll-Wrapper (no sticky)</h2>
77
+ <d2l-demo-snippet overflow-hidden>
78
+ <template>
79
+ <div style="height: 400px; overflow: auto;">
80
+ <d2l-test-table type="default" sticky-controls style="width: 400px;"></d2l-test-table>
81
+ </div>
82
+ </template>
83
+ </d2l-demo-snippet>
84
+
85
+ <h2>Scroll-wrapper + sticky</h2>
86
+ <d2l-demo-snippet>
87
+ <template>
88
+ <d2l-test-table sticky-headers sticky-controls sticky-headers-scroll-wrapper style="width: 400px;"></d2l-test-table>
89
+ </template>
90
+ </d2l-demo-snippet>
91
+
92
+ <h2>Multi-line with scroll-wrapper + sticky</h2>
93
+ <d2l-demo-snippet>
94
+ <template>
95
+ <d2l-test-table multi-line sticky-headers sticky-controls sticky-headers-scroll-wrapper style="width: 400px;"></d2l-test-table>
96
+ </template>
97
+ </d2l-demo-snippet>
98
+
99
+ <div style="margin-bottom: 1000px;"></div>
100
+ </d2l-demo-page>
101
+ <script>
102
+ document.querySelector('#print').addEventListener('click', () => {
103
+ window.print();
104
+ });
105
+ </script>
106
+ </body>
107
+ </html>
@@ -420,8 +420,10 @@ export class TableWrapper extends PageableMixin(SelectionMixin(LitElement)) {
420
420
 
421
421
  render() {
422
422
  const slot = html`
423
- <slot @slotchange="${this._handleSlotChange}"></slot>
424
- <d2l-backdrop-loading ?shown=${this.loading}></d2l-backdrop-loading>
423
+ <div style="position:relative">
424
+ <slot id="table-slot" @slotchange="${this._handleSlotChange}"></slot>
425
+ <d2l-backdrop-loading for="table-slot" ?shown=${this.loading}></d2l-backdrop-loading>
426
+ </div>
425
427
  `;
426
428
  const useScrollWrapper = this.stickyHeadersScrollWrapper || !this.stickyHeaders;
427
429
  return html`
@@ -191,6 +191,11 @@
191
191
  "path": "./components/backdrop/backdrop-loading.js",
192
192
  "description": "A component for displaying a semi-transparent backdrop and a loading spinner over the containing element",
193
193
  "attributes": [
194
+ {
195
+ "name": "for",
196
+ "description": "Used to identify content that the backdrop should make inert",
197
+ "type": "boolean"
198
+ },
194
199
  {
195
200
  "name": "shown",
196
201
  "description": "Used to control whether the loading backdrop is shown",
@@ -199,6 +204,12 @@
199
204
  }
200
205
  ],
201
206
  "properties": [
207
+ {
208
+ "name": "for",
209
+ "attribute": "for",
210
+ "description": "Used to identify content that the backdrop should make inert",
211
+ "type": "boolean"
212
+ },
202
213
  {
203
214
  "name": "shown",
204
215
  "attribute": "shown",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brightspace-ui/core",
3
- "version": "3.227.14",
3
+ "version": "3.227.16",
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",
@@ -40,6 +40,9 @@
40
40
  "!demo",
41
41
  "!test",
42
42
  "/components/demo",
43
+ "/components/description-list/demo",
44
+ "/components/selection/demo",
45
+ "/components/table/demo",
43
46
  "!/components/demo/demo"
44
47
  ],
45
48
  "author": "D2L Corporation",
@@ -54,7 +57,7 @@
54
57
  "chalk": "^5",
55
58
  "eslint": "^9",
56
59
  "eslint-config-brightspace": "^2.0.0",
57
- "eslint-plugin-unicorn": "^63",
60
+ "eslint-plugin-unicorn": "^64",
58
61
  "glob-all": "^3",
59
62
  "messageformat-validator": "^3.0.0-beta",
60
63
  "rollup": "^4",