@brightspace-ui/core 2.77.0 → 2.78.1
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/button/button-icon.js +1 -0
- package/components/collapsible-panel/README.md +28 -15
- package/components/list/README.md +67 -0
- package/components/list/demo/demo-list-nested-lazy-load.js +133 -0
- package/components/list/demo/demo-list-nested.js +279 -0
- package/components/list/demo/list-demo-scenarios.js +321 -0
- package/components/list/demo/list-drag-and-drop.html +2 -2
- package/components/list/demo/list-expand-collapse.html +134 -0
- package/components/list/list-item-checkbox-mixin.js +2 -8
- package/components/list/list-item-drag-drop-mixin.js +78 -14
- package/components/list/list-item-drag-image.js +5 -3
- package/components/list/list-item-expand-collapse-mixin.js +168 -0
- package/components/list/list-item-generic-layout.js +21 -12
- package/components/list/list-item-mixin.js +88 -11
- package/components/list/list.js +45 -9
- package/components/selection/selection-summary.js +43 -12
- package/custom-elements.json +386 -194
- package/lang/ar.js +1 -0
- package/lang/cy.js +1 -0
- package/lang/da.js +1 -0
- package/lang/de.js +1 -0
- package/lang/en.js +1 -0
- package/lang/es-es.js +1 -0
- package/lang/es.js +1 -0
- package/lang/fr-fr.js +1 -0
- package/lang/fr.js +1 -0
- package/lang/hi.js +1 -0
- package/lang/ja.js +1 -0
- package/lang/ko.js +1 -0
- package/lang/nl.js +1 -0
- package/lang/pt.js +1 -0
- package/lang/sv.js +1 -0
- package/lang/tr.js +1 -0
- package/lang/zh-cn.js +1 -0
- package/lang/zh-tw.js +1 -0
- package/package.json +1 -1
- package/components/list/demo/list-drag-and-drop.js +0 -181
|
@@ -62,6 +62,7 @@ class ButtonIcon extends ThemeMixin(ButtonMixin(VisibleOnAncestorMixin(RtlMixin(
|
|
|
62
62
|
--d2l-button-icon-h-align: calc(((2rem + 2px - 0.9rem) / 2) * -1);
|
|
63
63
|
--d2l-icon-fill-color: var(--d2l-button-icon-fill-color, var(--d2l-color-tungsten));
|
|
64
64
|
display: inline-block;
|
|
65
|
+
line-height: 0;
|
|
65
66
|
}
|
|
66
67
|
:host([hidden]) {
|
|
67
68
|
display: none;
|
|
@@ -97,17 +97,16 @@ The `d2l-collapsible-panel` element is a container that provides specific layout
|
|
|
97
97
|
|
|
98
98
|
<style>
|
|
99
99
|
d2l-collapsible-panel {
|
|
100
|
-
width:
|
|
101
|
-
margin-block: 2rem;
|
|
100
|
+
width: 800px;
|
|
102
101
|
}
|
|
103
102
|
/* TODO: remove this when daylight demo resizing is fixed */
|
|
104
103
|
d2l-collapsible-panel:not([expanded]) {
|
|
105
|
-
margin-bottom:
|
|
104
|
+
margin-bottom: 14rem;
|
|
106
105
|
}
|
|
107
106
|
</style>
|
|
108
107
|
|
|
109
|
-
<d2l-collapsible-panel panel-title="
|
|
110
|
-
|
|
108
|
+
<d2l-collapsible-panel panel-title="Collapsible Panel">
|
|
109
|
+
The collapsible panel is also nicknamed caketray! Team Polaris coined this nickname back in 2020 while creating a labs component for a tool called Learning Paths (which is now replaced with the collapsible panel). They wanted to distinguish this labs component from d2l-card, but they didn't know what to call it, so they named it caketray to serve as a reminder to change the name later. Caketray caught on around the company, so much so that we had to make it an official nickname so some teams could find it! You'll see some other cake-related examples throughout this documentation to pay tribute to the collapsible panel's heritage.
|
|
111
110
|
</d2l-collapsible-panel>
|
|
112
111
|
```
|
|
113
112
|
|
|
@@ -204,9 +203,7 @@ Use an inline collapsible panel to progressively disclose sections of a complex
|
|
|
204
203
|
## Summary Items [d2l-collapsible-panel-summary-item]
|
|
205
204
|
An optional summary can help the user understand what’s inside the collapsible panel without having to expand it. This can be helpful if the user needs more than the heading to explain what’s inside.
|
|
206
205
|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
<!-- docs: demo live -->
|
|
206
|
+
<!-- docs: demo -->
|
|
210
207
|
```html
|
|
211
208
|
<script type="module">
|
|
212
209
|
import '@brightspace-ui/core/components/collapsible-panel/collapsible-panel.js';
|
|
@@ -234,7 +231,7 @@ class CollapsiblePanelDaylightDemo extends LitElement {
|
|
|
234
231
|
}
|
|
235
232
|
/* TODO: remove this when daylight demo resizing is fixed */
|
|
236
233
|
d2l-collapsible-panel:not([expanded]) {
|
|
237
|
-
margin-bottom:
|
|
234
|
+
margin-bottom: 12rem;
|
|
238
235
|
}
|
|
239
236
|
`];
|
|
240
237
|
}
|
|
@@ -292,9 +289,26 @@ customElements.define('d2l-collapsible-panel-daylight-demo', CollapsiblePanelDay
|
|
|
292
289
|
<d2l-collapsible-panel-daylight-demo></d2l-collapsible-panel-daylight-demo>
|
|
293
290
|
```
|
|
294
291
|
|
|
295
|
-
|
|
292
|
+
More than one `d2l-collapsible-panel-summary-item` can be added to the `summary` slot, and each will appear on its own line.
|
|
293
|
+
|
|
294
|
+
```html
|
|
295
|
+
<script type="module">
|
|
296
|
+
import '@brightspace-ui/core/components/collapsible-panel/collapsible-panel.js';
|
|
297
|
+
import '@brightspace-ui/core/components/collapsible-panel/collapsible-panel-summary-item.js';
|
|
298
|
+
</script>
|
|
299
|
+
|
|
300
|
+
<d2l-collapsible-panel panel-title="Cake Decoration">
|
|
301
|
+
<d2l-collapsible-panel-summary-item slot="summary" text="Buttercream icing"></d2l-collapsible-panel-summary-item>
|
|
302
|
+
<d2l-collapsible-panel-summary-item slot="summary" text="Personalized name"></d2l-collapsible-panel-summary-item>
|
|
303
|
+
<d2l-collapsible-panel-summary-item slot="summary" text="Candles"></d2l-collapsible-panel-summary-item>
|
|
304
|
+
<d2l-collapsible-panel-summary-item slot="summary" text="Plates and Forks"></d2l-collapsible-panel-summary-item>
|
|
305
|
+
Expanded content
|
|
306
|
+
</d2l-collapsible-panel>
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
## Header and actions slots
|
|
296
310
|
|
|
297
|
-
Collapsible panels have two optional slots, `
|
|
311
|
+
Collapsible panels have two optional slots, `header` and `actions` that can be used to add more information to the header area.
|
|
298
312
|
|
|
299
313
|
|
|
300
314
|
<!-- docs: demo live -->
|
|
@@ -302,6 +316,7 @@ Collapsible panels have two optional slots, `actions` and `header` that can be u
|
|
|
302
316
|
<script type="module">
|
|
303
317
|
import '@brightspace-ui/core/components/button/button-icon.js';
|
|
304
318
|
import '@brightspace-ui/core/components/collapsible-panel/collapsible-panel.js';
|
|
319
|
+
import '@brightspace-ui/core/components/collapsible-panel/collapsible-panel-summary-item.js';
|
|
305
320
|
import '@brightspace-ui/core/components/dropdown/dropdown-more.js';
|
|
306
321
|
import '@brightspace-ui/core/components/dropdown/dropdown-menu.js';
|
|
307
322
|
import '@brightspace-ui/core/components/link/link.js';
|
|
@@ -314,10 +329,6 @@ Collapsible panels have two optional slots, `actions` and `header` that can be u
|
|
|
314
329
|
d2l-collapsible-panel {
|
|
315
330
|
width: 800px;
|
|
316
331
|
}
|
|
317
|
-
/* TODO: remove this when daylight demo resizing is fixed */
|
|
318
|
-
d2l-collapsible-panel:not([expanded]) {
|
|
319
|
-
margin-bottom: 4rem;
|
|
320
|
-
}
|
|
321
332
|
</style>
|
|
322
333
|
|
|
323
334
|
<d2l-collapsible-panel panel-title="Submission 1">
|
|
@@ -336,6 +347,8 @@ Collapsible panels have two optional slots, `actions` and `header` that can be u
|
|
|
336
347
|
<p class="d2l-body-small">Submitted On: Jul 20, 2021 - 2:23 PM</p>
|
|
337
348
|
<d2l-link small href="https://www.d2l.com" target="blank">Link to post</d2l-link>
|
|
338
349
|
</div>
|
|
350
|
+
<d2l-collapsible-panel-summary-item slot="summary" text="Week 2 Lab (PDF) attached"></d2l-collapsible-panel-summary-item>
|
|
351
|
+
<d2l-collapsible-panel-summary-item slot="summary" text="1 comment"></d2l-collapsible-panel-summary-item>
|
|
339
352
|
Expanded content
|
|
340
353
|
</d2l-collapsible-panel>
|
|
341
354
|
```
|
|
@@ -193,6 +193,67 @@ If a `d2l-list-item` is selectable then it should have a `label` attribute that
|
|
|
193
193
|
</d2l-list>
|
|
194
194
|
```
|
|
195
195
|
|
|
196
|
+
## Expandable Lists
|
|
197
|
+
|
|
198
|
+
The `d2l-list` supports expandable items within a list. Expand and collapse toggle is enabled when `d2l-list-item`s have the `expandable` and `key` attributes set. When items are expandable the default state is collapsed. If you would like the default state to be expanded, add the `expanded` attribute to the `d2l-list-item`.
|
|
199
|
+
|
|
200
|
+
### Expandable List Accessibility Properties
|
|
201
|
+
|
|
202
|
+
If a `d2l-list-item` is expandable then it should have a `label` attribute that corresponds to the hidden label for the expand/collapse toggle.
|
|
203
|
+
|
|
204
|
+
### Expandable List Example
|
|
205
|
+
|
|
206
|
+
<!-- docs: demo code autoSize:false size:medium -->
|
|
207
|
+
```html
|
|
208
|
+
<script type="module">
|
|
209
|
+
import '@brightspace-ui/core/components/list/list.js';
|
|
210
|
+
import '@brightspace-ui/core/components/list/list-header.js';
|
|
211
|
+
import '@brightspace-ui/core/components/list/list-item.js';
|
|
212
|
+
import '@brightspace-ui/core/components/list/list-item-content.js';
|
|
213
|
+
import '@brightspace-ui/core/components/selection/selection-action.js';
|
|
214
|
+
</script>
|
|
215
|
+
|
|
216
|
+
<d2l-list grid style="width: 100%">
|
|
217
|
+
<d2l-list-header slot="header">
|
|
218
|
+
<d2l-selection-action icon="tier1:delete" text="Delete" requires-selection></d2l-selection-action>
|
|
219
|
+
</d2l-list-header>
|
|
220
|
+
<d2l-list-item selectable expandable key="expand-1" label="Expandable item #1">
|
|
221
|
+
<d2l-list-item-content>
|
|
222
|
+
<div>Expandable item #1</div>
|
|
223
|
+
<div slot="supporting-info">Supporting information</div>
|
|
224
|
+
</d2l-list-item-content>
|
|
225
|
+
<d2l-list grid style="width: 100%" slot="nested">
|
|
226
|
+
<d2l-list-item selectable key="nested-1" label="Nested 1">
|
|
227
|
+
<d2l-list-item-content><div>Nested item #1</div></d2l-list-item-content>
|
|
228
|
+
</d2l-list-item>
|
|
229
|
+
<d2l-list-item selectable key="nested-2" label="Nested 2">
|
|
230
|
+
<d2l-list-item-content><div>Nested item #2</div></d2l-list-item-content>
|
|
231
|
+
</d2l-list-item>
|
|
232
|
+
</d2l-list>
|
|
233
|
+
</d2l-list-item>
|
|
234
|
+
<d2l-list-item selectable expandable expanded key="expand-2" label="Expandable item #2">
|
|
235
|
+
<d2l-list-item-content>
|
|
236
|
+
<div>Expandable Item #2</div>
|
|
237
|
+
<div slot="supporting-info">Supporting information</div>
|
|
238
|
+
</d2l-list-item-content>
|
|
239
|
+
<d2l-list grid style="width: 100%" slot="nested">
|
|
240
|
+
<d2l-list-item selectable key="nested-3" label="Nested 3">
|
|
241
|
+
<d2l-list-item-content><div>Nested item #3</div></d2l-list-item-content>
|
|
242
|
+
</d2l-list-item>
|
|
243
|
+
<d2l-list-item selectable key="nested-4" label="Nested 4">
|
|
244
|
+
<d2l-list-item-content><div>Nested item #4</div></d2l-list-item-content>
|
|
245
|
+
</d2l-list-item>
|
|
246
|
+
</d2l-list>
|
|
247
|
+
</d2l-list-item>
|
|
248
|
+
<d2l-list-item selectable key="expand-3" label="Item with no children">
|
|
249
|
+
<d2l-list-item-content>
|
|
250
|
+
<div>Item with no children</div>
|
|
251
|
+
<div slot="supporting-info">Supporting information</div>
|
|
252
|
+
</d2l-list-item-content>
|
|
253
|
+
</d2l-list-item>
|
|
254
|
+
</d2l-list>
|
|
255
|
+
```
|
|
256
|
+
|
|
196
257
|
## Pageable Lists
|
|
197
258
|
|
|
198
259
|
Load-More paging functionality can be implemented in lists by placing a `d2l-pager-load-more` in `d2l-list`'s `pager` slot. The consumer must handle the `d2l-pager-load-more` event by loading more items, updating the pager state, and signalling completion by calling `complete()` on the event detail. Focus will be automatically moved on the first new item once complete. See [Paging](../../components/paging) for more details.
|
|
@@ -347,6 +408,8 @@ The `d2l-list-item` provides the appropriate `listitem` semantics for children w
|
|
|
347
408
|
| `drag-target-handle-only` | Boolean | Make the drag target the drag handle only. |
|
|
348
409
|
| `drop-nested` | Boolean | Whether nested items can be dropped on this item |
|
|
349
410
|
| `drop-text` | String | Text to drag and drop |
|
|
411
|
+
| `expandable` | Boolean | Whether or not to show the expand/collapse toggle. |
|
|
412
|
+
| `expanded` | Boolean | Whether the item is expanded. Requires `expandable` to be set. |
|
|
350
413
|
| `href` | String | Address of item link if navigable |
|
|
351
414
|
| `key` | String | Value to identify item if selectable or draggable |
|
|
352
415
|
| `label` | String | Explicitly defined label for the element |
|
|
@@ -366,6 +429,7 @@ The `d2l-list-item` provides the appropriate `listitem` semantics for children w
|
|
|
366
429
|
### Events
|
|
367
430
|
|
|
368
431
|
- `d2l-list-item-link-click`: dispatched when the item's primary link action is clicked
|
|
432
|
+
- `d2l-list-item-expand-collapse-toggled`: dispatched when the item's expand/collapse toggle is clicked
|
|
369
433
|
<!-- docs: end hidden content -->
|
|
370
434
|
|
|
371
435
|
### Breakpoints Property
|
|
@@ -417,6 +481,8 @@ The `d2l-list-item-button` provides the same functionality as `d2l-list-item` ex
|
|
|
417
481
|
| `drag-handle-text` | String | The drag-handle label for assistive technology. If implementing drag & drop, you should change this to dynamically announce what the drag-handle is moving for assistive technology in keyboard mode. |
|
|
418
482
|
| `drop-nested` | Boolean | Whether nested items can be dropped on this item |
|
|
419
483
|
| `drop-text` | String | Text to drag and drop |
|
|
484
|
+
| `expandable` | Boolean | Whether or not to show the expand/collapse toggle. |
|
|
485
|
+
| `expanded` | Boolean | Whether the item is expanded. Requires `expandable` to be set. |
|
|
420
486
|
| `key` | String | Value to identify item if selectable or draggable |
|
|
421
487
|
| `label` | String | Explicitly defined label for the element |
|
|
422
488
|
| `labelled-by` | String | The id of element that provides the label for this element |
|
|
@@ -428,6 +494,7 @@ The `d2l-list-item-button` provides the same functionality as `d2l-list-item` ex
|
|
|
428
494
|
### Events
|
|
429
495
|
|
|
430
496
|
- `d2l-list-item-button-click`: dispatched when the item's primary button action is clicked
|
|
497
|
+
- `d2l-list-item-expand-collapse-toggled`: dispatched when the item's expand/collapse toggle is clicked
|
|
431
498
|
<!-- docs: end hidden content -->
|
|
432
499
|
|
|
433
500
|
## ListItemMixin
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import '../list-item-content.js';
|
|
2
|
+
import '../list-item.js';
|
|
3
|
+
import '../list.js';
|
|
4
|
+
import '../list-header.js';
|
|
5
|
+
import '../../selection/selection-action.js';
|
|
6
|
+
import { html, LitElement, nothing } from 'lit';
|
|
7
|
+
import { getUniqueId } from '../../../helpers/uniqueId.js';
|
|
8
|
+
import { ifDefined } from 'lit/directives/if-defined.js';
|
|
9
|
+
import { repeat } from 'lit/directives/repeat.js';
|
|
10
|
+
|
|
11
|
+
class ListDemoNestedLazyLoad extends LitElement {
|
|
12
|
+
|
|
13
|
+
static get properties() {
|
|
14
|
+
return {
|
|
15
|
+
_items: { state: true },
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
constructor() {
|
|
20
|
+
super();
|
|
21
|
+
this._items = new Map();
|
|
22
|
+
this._items.set('a', {
|
|
23
|
+
key: 'a',
|
|
24
|
+
primaryText: 'Item 1: Click Expand To Lazy Load Item',
|
|
25
|
+
items: [],
|
|
26
|
+
expandable: true,
|
|
27
|
+
selected: false
|
|
28
|
+
});
|
|
29
|
+
this._items.set('b', {
|
|
30
|
+
key: 'b',
|
|
31
|
+
primaryText: 'Item 2: Click Expand To Lazy Load Item',
|
|
32
|
+
items: [],
|
|
33
|
+
expandable: true,
|
|
34
|
+
selected: false
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
render() {
|
|
39
|
+
return html`
|
|
40
|
+
<div>
|
|
41
|
+
${this._renderList(this._items.values(), false, true)}
|
|
42
|
+
</div>
|
|
43
|
+
`;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
_handleListItemToggle(e) {
|
|
47
|
+
const listItem = e.target;
|
|
48
|
+
const itemKey = e.target.key;
|
|
49
|
+
const previouslyCollapsed = !e.target.expanded;
|
|
50
|
+
const itemToAddChildren = this._items.get(itemKey);
|
|
51
|
+
if (!previouslyCollapsed && itemToAddChildren.items.length === 0) {
|
|
52
|
+
if (listItem.selected) {
|
|
53
|
+
itemToAddChildren.selected = true;
|
|
54
|
+
}
|
|
55
|
+
const uniqueId = getUniqueId();
|
|
56
|
+
itemToAddChildren.items = [{
|
|
57
|
+
key: uniqueId,
|
|
58
|
+
primaryText: `Lazy Loaded Item ${uniqueId}`,
|
|
59
|
+
items: [],
|
|
60
|
+
expandable: false,
|
|
61
|
+
selected: listItem.selected
|
|
62
|
+
}];
|
|
63
|
+
|
|
64
|
+
setTimeout(() => {
|
|
65
|
+
// fake lazy loading items
|
|
66
|
+
this._items.set(itemKey, itemToAddChildren);
|
|
67
|
+
this.requestUpdate();
|
|
68
|
+
}, 2000);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
_renderIllustration(item) {
|
|
73
|
+
if (!item.imgSrc) {
|
|
74
|
+
return nothing;
|
|
75
|
+
}
|
|
76
|
+
return html`<img slot="illustration" src="${item.imgSrc}">`;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
_renderItemContent(item) {
|
|
80
|
+
return html`
|
|
81
|
+
<d2l-list-item-content>
|
|
82
|
+
<div>${item.primaryText}</div>
|
|
83
|
+
<div slot="supporting-info">${item.supportingText}</div>
|
|
84
|
+
</d2l-list-item-content>`;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
_renderList(items, nested, includeHeader = false) {
|
|
88
|
+
return html`
|
|
89
|
+
<d2l-list grid drag-multiple slot="${ifDefined(nested ? 'nested' : undefined)}">
|
|
90
|
+
${ includeHeader ? this._renderListHeader() : nothing }
|
|
91
|
+
${repeat(items, item => item.key, item => html`
|
|
92
|
+
${this._renderListItem(item)}
|
|
93
|
+
`)}
|
|
94
|
+
</d2l-list>
|
|
95
|
+
`;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
_renderListHeader() {
|
|
99
|
+
return html`
|
|
100
|
+
<d2l-list-header slot="header">
|
|
101
|
+
<d2l-selection-action icon="tier1:bookmark-hollow" text="Bookmark" requires-selection></d2l-selection-action>
|
|
102
|
+
<d2l-selection-action icon="tier1:gear" text="Settings"></d2l-selection-action>
|
|
103
|
+
</d2l-list-header>
|
|
104
|
+
`;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
_renderListItem(item) {
|
|
108
|
+
return html`
|
|
109
|
+
<d2l-list-item
|
|
110
|
+
draggable
|
|
111
|
+
selectable
|
|
112
|
+
?selected="${item.selected}"
|
|
113
|
+
drag-handle-text="${item.primaryText}"
|
|
114
|
+
key="${item.key}"
|
|
115
|
+
label="${item.primaryText}"
|
|
116
|
+
?expandable="${item.expandable}"
|
|
117
|
+
@d2l-list-item-expand-collapse-toggled="${this._handleListItemToggle}">
|
|
118
|
+
${this._renderIllustration(item)}
|
|
119
|
+
${this._renderItemContent(item)}
|
|
120
|
+
${this._renderNestedList(item)}
|
|
121
|
+
</d2l-list-item>
|
|
122
|
+
`;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
_renderNestedList(item) {
|
|
126
|
+
if (item?.items?.length <= 0) {
|
|
127
|
+
return nothing;
|
|
128
|
+
}
|
|
129
|
+
return this._renderList(item.items, true);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
customElements.define('d2l-demo-list-nested-lazy-load', ListDemoNestedLazyLoad);
|
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
import '../list-item-content.js';
|
|
2
|
+
import '../list-item.js';
|
|
3
|
+
import '../list-item-button.js';
|
|
4
|
+
import '../list.js';
|
|
5
|
+
import '../../dropdown/dropdown-menu.js';
|
|
6
|
+
import '../../dropdown/dropdown-more.js';
|
|
7
|
+
import '../../menu/menu.js';
|
|
8
|
+
import '../../menu/menu-item.js';
|
|
9
|
+
import '../../paging/pager-load-more.js';
|
|
10
|
+
import '../list-header.js';
|
|
11
|
+
import '../../selection/selection-action.js';
|
|
12
|
+
import { css, html, LitElement, nothing } from 'lit';
|
|
13
|
+
import { ifDefined } from 'lit/directives/if-defined.js';
|
|
14
|
+
import { listDemos } from './list-demo-scenarios.js';
|
|
15
|
+
import { moveLocations } from '../list-item-drag-drop-mixin.js';
|
|
16
|
+
import { repeat } from 'lit/directives/repeat.js';
|
|
17
|
+
|
|
18
|
+
class ListDemoNested extends LitElement {
|
|
19
|
+
|
|
20
|
+
static get properties() {
|
|
21
|
+
return {
|
|
22
|
+
demoItemKey: { type: String, attribute: 'demo-item-key' },
|
|
23
|
+
draggable: { type: Boolean },
|
|
24
|
+
selectable: { type: Boolean },
|
|
25
|
+
disableExpandFeature: { type: Boolean, attribute: 'disable-expand-feature' },
|
|
26
|
+
expanded: { type: Boolean },
|
|
27
|
+
includeSecondaryActions: { type: Boolean, attribute: 'include-secondary-actions' },
|
|
28
|
+
includeListHeader: { type: Boolean, attribute: 'include-list-header' },
|
|
29
|
+
includeActionHref: { type: Boolean, attribute: 'include-action-href' },
|
|
30
|
+
useButtonListItem: { type: Boolean, attribute: 'use-button-item' },
|
|
31
|
+
showLoadMore: { type: Boolean, attribute: 'show-load-more' },
|
|
32
|
+
noPrimaryAction: { type: Boolean, attribute: 'no-primary-action' },
|
|
33
|
+
disableListGrid: { type: Boolean, attribute: 'disable-list-grid' },
|
|
34
|
+
_items: { state: true },
|
|
35
|
+
_loadedItems: { state: true },
|
|
36
|
+
_remainingItemCount: { state: true },
|
|
37
|
+
_lastItemLoadedIndex: { state: true }
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
static get styles() {
|
|
42
|
+
return [
|
|
43
|
+
css`
|
|
44
|
+
.secondary-actions {
|
|
45
|
+
padding-right: 6px;
|
|
46
|
+
}
|
|
47
|
+
`
|
|
48
|
+
];
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
constructor() {
|
|
52
|
+
super();
|
|
53
|
+
this._items = [];
|
|
54
|
+
this._loadedItems = [];
|
|
55
|
+
this._remainingItemCount = 0;
|
|
56
|
+
this._lastItemLoadedIndex = 1;
|
|
57
|
+
this._pageSize = 1;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
render() {
|
|
61
|
+
return html`
|
|
62
|
+
<div @d2l-list-items-move="${this._handleListItemsMove}">
|
|
63
|
+
${this._renderList(this._loadedItems, false, this.includeListHeader, this.showLoadMore)}
|
|
64
|
+
</div>
|
|
65
|
+
`;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
updated(changedProperties) {
|
|
69
|
+
super.updated(changedProperties);
|
|
70
|
+
if (changedProperties.has('demoItemKey')) {
|
|
71
|
+
this._items = listDemos[this.demoItemKey] ?? [];
|
|
72
|
+
this._loadedItems = this._items;
|
|
73
|
+
}
|
|
74
|
+
if (changedProperties.has('_items') || changedProperties.has('demoItemKey') || changedProperties.has('showLoadMore') || changedProperties.has('_lastItemLoadedIndex')) {
|
|
75
|
+
this._loadedItems = this.showLoadMore ? this._items.slice(0, this._lastItemLoadedIndex + 1) : this._items;
|
|
76
|
+
this._remainingItemCount = this.showLoadMore ? this._items.length - this._loadedItems.length : 0;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
_handleButtonClick(e) {
|
|
81
|
+
// eslint-disable-next-line no-console
|
|
82
|
+
console.log('d2l-list-item-button clicked!', e);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
async _handleListItemsMove(e) {
|
|
86
|
+
|
|
87
|
+
const sourceListItems = e.detail.sourceItems;
|
|
88
|
+
const target = e.detail.target;
|
|
89
|
+
|
|
90
|
+
// helper that gets the array containing item data, the item data, and the index within the array
|
|
91
|
+
const getItemInfo = (items, key) => {
|
|
92
|
+
for (let i = 0; i < items.length; i++) {
|
|
93
|
+
if (items[i].key === key) {
|
|
94
|
+
return { owner: items, item: items[i], index: i };
|
|
95
|
+
}
|
|
96
|
+
if (items[i].items && items[i].items.length > 0) {
|
|
97
|
+
const tempItemData = getItemInfo(items[i].items, key);
|
|
98
|
+
if (tempItemData) return tempItemData;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
const dataToMove = [];
|
|
104
|
+
|
|
105
|
+
// remove data elements from original locations
|
|
106
|
+
sourceListItems.forEach(sourceListItem => {
|
|
107
|
+
const info = getItemInfo(this._items, sourceListItem.key);
|
|
108
|
+
if (info?.owner) {
|
|
109
|
+
info.owner.splice(info.index, 1);
|
|
110
|
+
}
|
|
111
|
+
if (info?.item) {
|
|
112
|
+
dataToMove.push(info.item);
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
// append data elements to new location
|
|
117
|
+
const targetInfo = getItemInfo(this._items, target.item.key);
|
|
118
|
+
let targetItems;
|
|
119
|
+
let targetIndex;
|
|
120
|
+
if (target.location === moveLocations.nest) {
|
|
121
|
+
if (!targetInfo.item.items) targetInfo.item.items = [];
|
|
122
|
+
targetItems = targetInfo.item.items;
|
|
123
|
+
targetIndex = targetItems.length;
|
|
124
|
+
} else {
|
|
125
|
+
targetItems = targetInfo?.owner;
|
|
126
|
+
if (!targetItems) return;
|
|
127
|
+
if (target.location === moveLocations.above) targetIndex = targetInfo.index;
|
|
128
|
+
else if (target.location === moveLocations.below) targetIndex = targetInfo.index + 1;
|
|
129
|
+
}
|
|
130
|
+
for (let i = dataToMove.length - 1; i >= 0; i--) {
|
|
131
|
+
targetItems.splice(targetIndex, 0, dataToMove[i]);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
this.requestUpdate();
|
|
135
|
+
await this.updateComplete;
|
|
136
|
+
|
|
137
|
+
if (e.detail.keyboardActive) {
|
|
138
|
+
setTimeout(() => {
|
|
139
|
+
if (!this.shadowRoot) return;
|
|
140
|
+
const newItem = this.shadowRoot.querySelector('d2l-list').getListItemByKey(sourceListItems[0].key);
|
|
141
|
+
newItem.activateDragHandle();
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
_handlePagerLoadMore(e) {
|
|
148
|
+
// mock delay consumers might have
|
|
149
|
+
setTimeout(() => {
|
|
150
|
+
this._lastItemLoadedIndex += this._pageSize;
|
|
151
|
+
e.detail.complete();
|
|
152
|
+
}, 1000);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
_renderIllustration(item) {
|
|
156
|
+
if (!item.imgSrc) {
|
|
157
|
+
return nothing;
|
|
158
|
+
}
|
|
159
|
+
return html`<img slot="illustration" src="${item.imgSrc}">`;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
_renderItemContent(item) {
|
|
163
|
+
return html`
|
|
164
|
+
<d2l-list-item-content>
|
|
165
|
+
<div>${item.primaryText}</div>
|
|
166
|
+
<div slot="supporting-info">${item.supportingText}</div>
|
|
167
|
+
</d2l-list-item-content>`;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
_renderList(items, nested, includeHeader = false, showLoadMore = false) {
|
|
171
|
+
return html`
|
|
172
|
+
<d2l-list ?grid="${!this.disableListGrid}" drag-multiple slot="${ifDefined(nested ? 'nested' : undefined)}">
|
|
173
|
+
${ includeHeader ? this._renderListHeader() : nothing }
|
|
174
|
+
${repeat(items, item => item.key, item => html`
|
|
175
|
+
${this._renderListItem(item)}
|
|
176
|
+
${this._renderListItemButton(item)}
|
|
177
|
+
`)}
|
|
178
|
+
${ showLoadMore ? this._renderShowLoadMore() : nothing }
|
|
179
|
+
</d2l-list>
|
|
180
|
+
`;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
_renderListHeader() {
|
|
184
|
+
return html`
|
|
185
|
+
<d2l-list-header slot="header">
|
|
186
|
+
<d2l-selection-action icon="tier1:bookmark-hollow" text="Bookmark" requires-selection></d2l-selection-action>
|
|
187
|
+
<d2l-selection-action icon="tier1:gear" text="Settings"></d2l-selection-action>
|
|
188
|
+
</d2l-list-header>
|
|
189
|
+
`;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
_renderListItem(item) {
|
|
193
|
+
if (this.useButtonListItem) {
|
|
194
|
+
return nothing;
|
|
195
|
+
}
|
|
196
|
+
const hasChildren = item?.items?.length > 0;
|
|
197
|
+
return html`
|
|
198
|
+
<d2l-list-item
|
|
199
|
+
action-href="${this.includeActionHref ? 'http://www.d2l.com' : ''}"
|
|
200
|
+
?draggable="${this.draggable}"
|
|
201
|
+
drag-handle-text="${item.primaryText}"
|
|
202
|
+
?drop-nested="${item.dropNested}"
|
|
203
|
+
key="${item.key}"
|
|
204
|
+
label="${item.primaryText}"
|
|
205
|
+
?selectable="${this.selectable}"
|
|
206
|
+
?expandable="${this.disableExpandFeature ? false : hasChildren}"
|
|
207
|
+
?expanded="${this.expanded}"
|
|
208
|
+
?no-primary-action="${this.noPrimaryAction}">
|
|
209
|
+
${this._renderIllustration(item)}
|
|
210
|
+
${this._renderItemContent(item)}
|
|
211
|
+
${this._renderSecondaryActions()}
|
|
212
|
+
${this._renderNestedList(item)}
|
|
213
|
+
</d2l-list-item>
|
|
214
|
+
`;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
_renderListItemButton(item) {
|
|
218
|
+
if (!this.useButtonListItem) {
|
|
219
|
+
return nothing;
|
|
220
|
+
}
|
|
221
|
+
const hasChildren = item?.items?.length > 0;
|
|
222
|
+
return html`
|
|
223
|
+
<d2l-list-item-button
|
|
224
|
+
?draggable="${this.draggable}"
|
|
225
|
+
drag-handle-text="${item.primaryText}"
|
|
226
|
+
?drop-nested="${item.dropNested}"
|
|
227
|
+
key="${item.key}"
|
|
228
|
+
label="${item.primaryText}"
|
|
229
|
+
?selectable="${this.selectable}"
|
|
230
|
+
?expandable="${this.disableExpandFeature ? false : hasChildren}"
|
|
231
|
+
?expanded="${this.expanded}"
|
|
232
|
+
@d2l-list-item-button-click="${this._handleButtonClick}">
|
|
233
|
+
${this._renderIllustration(item)}
|
|
234
|
+
${this._renderItemContent(item)}
|
|
235
|
+
${this._renderSecondaryActions()}
|
|
236
|
+
${this._renderNestedList(item)}
|
|
237
|
+
</d2l-list-item-button>
|
|
238
|
+
`;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
_renderNestedList(item) {
|
|
242
|
+
if (item?.items?.length <= 0) {
|
|
243
|
+
return nothing;
|
|
244
|
+
}
|
|
245
|
+
return this._renderList(item.items, true);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
_renderSecondaryActions() {
|
|
249
|
+
if (!this.includeSecondaryActions) {
|
|
250
|
+
return nothing;
|
|
251
|
+
}
|
|
252
|
+
return html`
|
|
253
|
+
<div slot="actions" class="secondary-actions">
|
|
254
|
+
<d2l-dropdown-more text="Open!">
|
|
255
|
+
<d2l-dropdown-menu>
|
|
256
|
+
<d2l-menu label="More Actions">
|
|
257
|
+
<d2l-menu-item text="Action 1"></d2l-menu-item>
|
|
258
|
+
<d2l-menu-item text="Action 2"></d2l-menu-item>
|
|
259
|
+
</d2l-menu>
|
|
260
|
+
</d2l-dropdown-menu>
|
|
261
|
+
</d2l-dropdown-more>
|
|
262
|
+
</div>
|
|
263
|
+
`;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
_renderShowLoadMore() {
|
|
267
|
+
return html`
|
|
268
|
+
<d2l-pager-load-more slot="pager"
|
|
269
|
+
@d2l-pager-load-more="${this._handlePagerLoadMore}"
|
|
270
|
+
?has-more="${this._lastItemLoadedIndex < this._items.length - 1}"
|
|
271
|
+
item-count="${this._items.length}"
|
|
272
|
+
page-size="${this._remainingItemCount < this._pageSize ? this._remainingItemCount : this._pageSize}">
|
|
273
|
+
</d2l-pager-load-more>
|
|
274
|
+
`;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
customElements.define('d2l-demo-list-nested', ListDemoNested);
|