@brightspace-ui/core 1.211.0 → 1.213.2

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/README.md CHANGED
@@ -55,6 +55,8 @@ npm install @brightspace-ui/core
55
55
  * [Tooltip](components/tooltip/): tooltip components
56
56
  * [Typography](components/typography/): typography styles and components
57
57
  * [Validation](components/validation/): plugin custom validation logic to native and custom form elements
58
+ * Controllers
59
+ * [Subscriber](controllers/subscriber/): for managing a registry of subscribers in a many-to-many relationship
58
60
  * Directives
59
61
  * [Animate](directives/animate/): animate showing, hiding and removal of elements
60
62
  * Helpers
@@ -212,6 +212,25 @@ class Filter extends LocalizeCoreElement(RtlMixin(LitElement)) {
212
212
  `;
213
213
  }
214
214
 
215
+ focus() {
216
+ const opener = this.shadowRoot.querySelector('d2l-dropdown-button-subtle');
217
+ if (opener) opener.focus();
218
+ }
219
+
220
+ requestFilterClearAll() {
221
+ this._handleClearAll();
222
+ }
223
+
224
+ requestFilterValueClear(keyObject) {
225
+ const dimension = this._dimensions.find(dimension => dimension.key === keyObject.dimension);
226
+
227
+ switch (dimension.type) {
228
+ case 'd2l-filter-dimension-set':
229
+ this._performChangeSetDimension(dimension, keyObject.value, false);
230
+ break;
231
+ }
232
+ }
233
+
215
234
  _buildDimension(dimension, singleDimension) {
216
235
  let dimensionHTML;
217
236
  switch (dimension.type) {
@@ -433,20 +452,9 @@ class Filter extends LocalizeCoreElement(RtlMixin(LitElement)) {
433
452
  const dimensionKey = e.target.id.slice(SET_DIMENSION_ID_PREFIX.length);
434
453
  const dimension = this._dimensions.find(dimension => dimension.key === dimensionKey);
435
454
  const valueKey = e.detail.key;
436
- const value = dimension.values.find(value => value.key === valueKey);
437
455
  const selected = e.detail.selected;
438
456
 
439
- value.selected = selected;
440
-
441
- if (selected) {
442
- dimension.appliedCount++;
443
- this._totalAppliedCount++;
444
- } else {
445
- dimension.appliedCount--;
446
- this._totalAppliedCount--;
447
- }
448
-
449
- this._dispatchChangeEvent(dimension, { valueKey: valueKey, selected: selected });
457
+ this._performChangeSetDimension(dimension, valueKey, selected);
450
458
  }
451
459
 
452
460
  _handleClear() {
@@ -621,6 +629,22 @@ class Filter extends LocalizeCoreElement(RtlMixin(LitElement)) {
621
629
  return false;
622
630
  }
623
631
 
632
+ _performChangeSetDimension(dimension, valueKey, selected) {
633
+ const value = dimension.values.find(value => value.key === valueKey);
634
+ if (value.selected === selected) return;
635
+ value.selected = selected;
636
+
637
+ if (selected) {
638
+ dimension.appliedCount++;
639
+ this._totalAppliedCount++;
640
+ } else {
641
+ dimension.appliedCount--;
642
+ this._totalAppliedCount--;
643
+ }
644
+
645
+ this._dispatchChangeEvent(dimension, { valueKey: valueKey, selected: selected });
646
+ }
647
+
624
648
  _performDimensionClear(dimension) {
625
649
  this._totalAppliedCount = this._totalAppliedCount - dimension.appliedCount;
626
650
  dimension.appliedCount = 0;
@@ -1,6 +1,6 @@
1
1
  import '../colors/colors.js';
2
2
  import { css, LitElement } from 'lit-element/lit-element.js';
3
- import { HtmlAttributeObserverController } from '../../helpers/htmlAttributeObserverController.js';
3
+ import { HtmlAttributeObserverController } from '../../controllers/attributeObserver/htmlAttributeObserverController.js';
4
4
  import { HtmlBlockMathRenderer } from '../../helpers/mathjax.js';
5
5
  import { requestInstance } from '../../mixins/provider-mixin.js';
6
6
 
@@ -137,6 +137,7 @@ The `d2l-list` is the container to create a styled list of items using `d2l-list
137
137
 
138
138
  | Property | Type | Description |
139
139
  |---|---|---|
140
+ | `drag-multiple` | Boolean | Whether the user can drag multiple items |
140
141
  | `grid` | Boolean | Enables keyboard grid for supported list items. See [Accessibility](#accessibility). |
141
142
  | `selection-single` | Boolean | Whether to render with single selection behaviour. If `selection-single` is specified, the list-items will render with radios instead of checkboxes, and the list component will maintain a single selected item. |
142
143
  | `separators` | String | Display separators (`all` (default), `between`, `none`) |
@@ -150,18 +151,20 @@ The `d2l-list` is the container to create a styled list of items using `d2l-list
150
151
 
151
152
  ### Methods
152
153
 
153
- - `getListItemCount`: returns the length of the items within the list
154
- - `getListItemIndex` (Object): returns the index of the given element within the list
155
- - `getSelectedListItems` (Array): returns the selected items; pass `true` to include nested lists
156
- - `getSelectionInfo` (Object): returns a `SelectionInfo` object containing the `state` (`none`, `some`, `all`), and the `keys` (Array) for the selected items
154
+ - `getItems()` (Array): returns the list items within the list
155
+ - `getListItemByKey(key)` (ListItem): returns the list item element from the root or nested lists for the specified key
156
+ - `getListItemCount()` (Number): returns the number of items within the list
157
+ - `getListItemIndex(item)` (Object): returns the index of the given element within the list
158
+ - `getSelectedListItems(includeNested)` (Array): returns the selected items; pass `true` to include nested lists
159
+ - `getSelectionInfo(includeNested)` (Object): returns a `SelectionInfo` object containing the `state` (`none`, `some`, `all`), and the `keys` (Array) for the selected items
157
160
 
158
161
  ## Selection Lists
159
162
 
160
- The `d2l-list` supports selectable items within a list, including both single and multi. Selection is enabled when a `d2l-list-item` has the `selectable` attribute set on it, and is by default multi-select which is indicated by a checkbox. Setting `selection-single` on the `d2l-list` wrapper enables single selection, which renders the selectable items with radio buttons. A `d2l-list-header` component can be added before the `d2l-list-item` component in order to have an easy multi-select header with actions.
163
+ The `d2l-list` supports selectable items within a list, including both single and multi selection. Selection is enabled when `d2l-list-item`s have the `selectable` attribute. When items are selectable, multiple selection is the default behaviour, however the `selection-single` attribute can be applied to the `d2l-list` to enable single selection. A `d2l-list-header` component can be added to `d2l-list`'s `header` slot to provide select-all and bulk actions.
161
164
 
162
165
  ### Accessibility Properties
163
166
 
164
- If a `d2l-list-item` is selectable then it should have a `label` attribute set on it which corresponds to the hidden label for the checkbox.
167
+ If a `d2l-list-item` is selectable then it should have a `label` attribute that corresponds to the hidden label for the checkbox.
165
168
 
166
169
  ### Example
167
170
 
@@ -202,12 +205,15 @@ The `d2l-list` supports drag & drop.
202
205
  ![List](./screenshots/drag-and-drop.gif?raw=true)
203
206
  <!-- docs: end hidden content -->
204
207
 
205
- Because the list itself is a rendering component, there is some light work involved in hooking up this behaviour.
208
+ The `d2l-list` is simply a rendering component, so there is some light work involved in hooking up this behaviour. In order for items to be draggable, they must have their `draggable` and `key` attributes set. Optionally, the `drop-nested` attribute can be applied to items to indicate whether other items can be dropped as nested children on the item.
206
209
 
207
- - `d2l-list-item` components within the list must be `draggable` and have `key` set to something unique
208
- - Reordering and re-rendering is the controlling component's responsibility
210
+ Reordering and re-rendering is the consuming component's responsibility. For a simple flat list, listen for the `d2l-list-item-position-change` event and call the `reorder` helper method. Alternatively, or for more complex lists such as those with nested lists, listen for the `d2l-list-items-move` event on the root list and update the consumer data using the provided source and target event detail.
209
211
 
210
- Here is a simple component example that adds drag 'n' drop to a list:
212
+ ### Accessibility Properties
213
+
214
+ If an item is draggable, the `drag-handle-text` attribute should be used to provide an accessible label for assistive technology in keyboard mode.
215
+
216
+ ### Example
211
217
 
212
218
  <!-- docs: demo code autoSize:false size:medium -->
213
219
  ```html
@@ -227,18 +233,9 @@ Here is a simple component example that adds drag 'n' drop to a list:
227
233
  constructor() {
228
234
  super();
229
235
  this.list = [
230
- {
231
- key: '1',
232
- content: 'Initially first list item'
233
- },
234
- {
235
- key: '2',
236
- content: 'Initially second list item'
237
- },
238
- {
239
- key: '3',
240
- content: 'Initially third list item'
241
- }
236
+ { key: '1', content: 'Initially first list item' },
237
+ { key: '2', content: 'Initially second list item' },
238
+ { key: '3', content: 'Initially third list item' }
242
239
  ];
243
240
  }
244
241
 
@@ -319,7 +316,7 @@ The `d2l-list-header` component can be placed in the `d2l-list`'s `header` slot
319
316
 
320
317
  ## List Item [d2l-list-item]
321
318
 
322
- The `d2l-list-item` provides the appropriate `listitem` semantics for children within a list. It also provides some basic layout, breakpoints for responsiveness, a navigation link for the primary action, and selection. It extends `ListItemLinkMixin` and `ListItemMixin` and has all the same use cases as the mixin.
319
+ The `d2l-list-item` provides the appropriate `listitem` semantics for children within a list. It also provides some basic layout, breakpoints for responsiveness, a navigation link for the primary action, and selection.
323
320
 
324
321
  <!-- docs: start hidden content -->
325
322
  ![List](./screenshots/list-item.png?raw=true)
@@ -353,7 +350,20 @@ The `d2l-list-item` provides the appropriate `listitem` semantics for children w
353
350
 
354
351
  | Property | Type | Description |
355
352
  |---|---|---|
353
+ | `breakpoints` | Array | Breakpoints for responsiveness in pixels. There are four different breakpoints and only the four largest breakpoints will be used. |
354
+ | `disabled` | Boolean | Disables the input |
355
+ | `draggable` | Boolean | Whether the item is draggable |
356
+ | `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. |
357
+ | `drop-nested` | Boolean | Whether nested items can be dropped on this item |
358
+ | `drop-text` | String | Text to drag and drop |
356
359
  | `href` | String | Address of item link if navigable |
360
+ | `key` | String | Value to identify item if selectable or draggable |
361
+ | `label` | String | Explicitly defined label for the element |
362
+ | `labelled-by` | String | The id of element that provides the label for this element |
363
+ | `selectable` | Boolean | Indicates an input should be rendered for selecting the item |
364
+ | `selected` | Boolean | Whether the item is selected |
365
+ | `skeleton` | Boolean | Renders the input as a skeleton loader |
366
+ | `slim` | Boolean | Whether to render the list-item with reduced whitespace|
357
367
 
358
368
  ### Events
359
369
 
@@ -376,6 +386,56 @@ The `d2l-list-item` provides the appropriate `listitem` semantics for children w
376
386
  - Image: max dimensions: `width: 216px` and `height: 120px` and has `20px margin` from the main content;
377
387
  - default break: `843px < x` where `x` is the width of the component.
378
388
 
389
+ ## Button List Item [d2l-list-item-button]
390
+
391
+ The `d2l-list-item-button` provides the same functionality as `d2l-list-item` except with button semantics for its primary action.
392
+
393
+ <!-- docs: start hidden content -->
394
+ ![List](./screenshots/list-item.png?raw=true)
395
+ <!-- docs: end hidden content -->
396
+
397
+ <!-- docs: demo live name:d2l-list-item-button -->
398
+ ```html
399
+ <script type="module">
400
+ import '@brightspace-ui/core/components/list/list.js';
401
+ import '@brightspace-ui/core/components/list/list-item-button.js';
402
+ import '@brightspace-ui/core/components/list/list-item-content.js';
403
+ </script>
404
+
405
+ <d2l-list style="width: 100%">
406
+ <d2l-list-item-button href="http://www.d2l.com" selectable key="1" label="Geomorphology and GIS">
407
+ <d2l-list-item-content>
408
+ <div>Geomorphology and GIS </div>
409
+ <div slot="supporting-info">This course explores the geological processes of the Earth's interior and surface. These include volcanism, earthquakes, mountain...</div>
410
+ </d2l-list-item-content>
411
+ </d2l-list-item-button>
412
+ </d2l-list>
413
+ ```
414
+
415
+ <!-- docs: start hidden content -->
416
+ ### Properties
417
+
418
+ | Property | Type | Description |
419
+ |---|---|---|
420
+ | `breakpoints` | Array | Breakpoints for responsiveness in pixels. There are four different breakpoints and only the four largest breakpoints will be used. |
421
+ | `disabled` | Boolean | Disables the input |
422
+ | `draggable` | Boolean | Whether the item is draggable |
423
+ | `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. |
424
+ | `drop-nested` | Boolean | Whether nested items can be dropped on this item |
425
+ | `drop-text` | String | Text to drag and drop |
426
+ | `key` | String | Value to identify item if selectable or draggable |
427
+ | `label` | String | Explicitly defined label for the element |
428
+ | `labelled-by` | String | The id of element that provides the label for this element |
429
+ | `selectable` | Boolean | Indicates an input should be rendered for selecting the item |
430
+ | `selected` | Boolean | Whether the item is selected |
431
+ | `skeleton` | Boolean | Renders the input as a skeleton loader |
432
+ | `slim` | Boolean | Whether to render the list-item with reduced whitespace|
433
+
434
+ ### Events
435
+
436
+ - `d2l-list-item-button-click`: dispatched when the item's primary button action is clicked
437
+ <!-- docs: end hidden content -->
438
+
379
439
  ## ListItemMixin
380
440
 
381
441
  Want to maintain consistency with `d2l-list-item` but need more modularity? This mixin is for you! This mixin allows you to make a component into a list item without requiring custom styling. All of the properties and functionality from `d2l-list-item` (listed above) will be added to your new component.
@@ -411,42 +471,7 @@ Where the parameters correspond to the slots of `d2l-list-item`:
411
471
  - illustration (TemplateResult): Provide an illustration for your list item.
412
472
  - content (TemplateResult): Core content of the list item, such as a d2l-list-item-content element.
413
473
  - actions (TemplateResult): Secondary actions for the list item.
414
-
415
- ### Accessibility Properties
416
-
417
- - `drag-handle-text`: 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
-
419
- ## Button List Item [d2l-list-item-button]
420
-
421
- The `d2l-list-item-button` provides the same functionality as `d2l-list-item` except with button semantics for its primary action. It extends `ListItemButtonMixin` and `ListItemMixin` and has all the same use cases as the mixin.
422
-
423
- <!-- docs: start hidden content -->
424
- ![List](./screenshots/list-item.png?raw=true)
425
- <!-- docs: end hidden content -->
426
-
427
- <!-- docs: demo live name:d2l-list-item-button -->
428
- ```html
429
- <script type="module">
430
- import '@brightspace-ui/core/components/list/list.js';
431
- import '@brightspace-ui/core/components/list/list-item-button.js';
432
- import '@brightspace-ui/core/components/list/list-item-content.js';
433
- </script>
434
-
435
- <d2l-list style="width: 100%">
436
- <d2l-list-item-button href="http://www.d2l.com" selectable key="1" label="Geomorphology and GIS">
437
- <d2l-list-item-content>
438
- <div>Geomorphology and GIS </div>
439
- <div slot="supporting-info">This course explores the geological processes of the Earth's interior and surface. These include volcanism, earthquakes, mountain...</div>
440
- </d2l-list-item-content>
441
- </d2l-list-item-button>
442
- </d2l-list>
443
- ```
444
-
445
- <!-- docs: start hidden content -->
446
- ### Events
447
-
448
- - `d2l-list-item-button-click`: dispatched when the item's primary button action is clicked
449
- <!-- docs: end hidden content -->
474
+ - nested (TemplateResult): Optional `d2l-list` for a nested list.
450
475
 
451
476
  ## List Item Content
452
477
 
@@ -494,6 +519,13 @@ This event includes a detail object with helper methods attached to it.
494
519
  - `announceFn(any, Number) (optional)`: A callback function that takes a given item in the array and its index, and returns the text to announce
495
520
  - `keyFn(any)`: A callback function that takes a given item in the array and returns its key
496
521
 
522
+ ## Event Details: @d2l-list-items-move
523
+
524
+ **Properties**
525
+
526
+ - `keyboardActive`: (Boolean) Whether the drag handle is in keyboard mode
527
+ - `sourceItems`: (Array) Items being moved
528
+ - `target`: (Object) The target reference `item` where items are being moved, and the `location` (`moveLocations.above`, `moveLocations.below`, or `moveLocations.nest`)
497
529
 
498
530
  <!-- docs: start hidden content -->
499
531
  ## Future Improvements
@@ -21,23 +21,27 @@ class ListDemoDragAndDrop extends LitElement {
21
21
  primaryText: 'Introductory Earth Sciences',
22
22
  supportingText: 'This course explores the geological processes of the Earth\'s interior and surface. These include volcanism, earthquakes, mountain building, glaciation and weathering.',
23
23
  imgSrc: 'https://s.brightspace.com/course-images/images/63b162ab-b582-4bf9-8c1d-1dad04714121/tile-high-density-max-size.jpg',
24
+ dropNested: true,
24
25
  items: [{
25
26
  key: '1-1',
26
27
  primaryText: 'Glaciation',
27
- supportingText: 'Supporting Info',
28
- imgSrc: '',
28
+ supportingText: 'Nesting Allowed',
29
+ imgSrc: 'https://s.brightspace.com/course-images/images/bf648978-6637-4fdc-815b-81572c436c0e/tile-high-density-max-size.jpg',
30
+ dropNested: true,
29
31
  items: []
30
32
  }, {
31
33
  key: '1-2',
32
34
  primaryText: 'Weathering',
33
- supportingText: 'Supporting Info',
34
- imgSrc: '',
35
+ supportingText: 'Nesting Allowed',
36
+ imgSrc: 'https://s.brightspace.com/course-images/images/50f91ba6-7c25-482a-bd71-1c4b7c8d2154/tile-high-density-min-size.jpg',
37
+ dropNested: true,
35
38
  items: []
36
39
  }, {
37
40
  key: '1-3',
38
41
  primaryText: 'Volcanism',
39
- supportingText: 'Supporting Info',
40
- imgSrc: '',
42
+ supportingText: 'Nesting Allowed',
43
+ imgSrc: 'https://s.brightspace.com/course-images/images/5eb2371d-6099-4c8d-8aad-075f357012a2/tile-high-density-min-size.jpg',
44
+ dropNested: true,
41
45
  items: []
42
46
  }]
43
47
  }, {
@@ -48,14 +52,16 @@ class ListDemoDragAndDrop extends LitElement {
48
52
  items: [{
49
53
  key: '2-1',
50
54
  primaryText: 'Contaminant Transport',
51
- supportingText: 'Supporting Info',
52
- imgSrc: '',
55
+ supportingText: 'No Nesting Allowed',
56
+ imgSrc: 'https://s.brightspace.com/course-images/images/824fffa1-86a6-4489-84ba-91edfbc1dcc4/tile-high-density-min-size.jpg',
57
+ dropNested: false,
53
58
  items: []
54
59
  }, {
55
60
  key: '2-2',
56
61
  primaryText: 'Modelling Flow in Fractured Media',
57
- supportingText: 'Supporting Info',
58
- imgSrc: '',
62
+ supportingText: 'No Nesting Allowed',
63
+ imgSrc: 'https://s.brightspace.com/course-images/images/e18c92a4-b996-444f-84b5-988874feccac/tile-high-density-min-size.jpg',
64
+ dropNested: false,
59
65
  items: []
60
66
  }]
61
67
  }, {
@@ -66,14 +72,16 @@ class ListDemoDragAndDrop extends LitElement {
66
72
  items: [{
67
73
  key: '3-1',
68
74
  primaryText: 'Carbon & Nitrogen Cycling',
69
- supportingText: 'Supporting Info',
70
- imgSrc: '',
75
+ supportingText: 'Nesting Allowed',
76
+ imgSrc: 'https://s.brightspace.com/course-images/images/623b420b-a305-4762-8af8-598f0e72e956/tile-high-density-min-size.jpg',
77
+ dropNested: true,
71
78
  items: []
72
79
  }, {
73
80
  key: '3-2',
74
81
  primaryText: 'Wetland Engineering',
75
- supportingText: 'Supporting Info',
76
- imgSrc: '',
82
+ supportingText: 'Nesting Allowed',
83
+ imgSrc: 'https://s.brightspace.com/course-images/images/26102577-8f2a-4e24-84b5-19d76decbc7a/tile-high-density-min-size.jpg',
84
+ dropNested: true,
77
85
  items: []
78
86
  }]
79
87
  }];
@@ -88,11 +96,11 @@ class ListDemoDragAndDrop extends LitElement {
88
96
  action-href="http://www.d2l.com"
89
97
  draggable
90
98
  drag-handle-text="${item.primaryText}"
91
- drop-nested
99
+ ?drop-nested="${item.dropNested}"
92
100
  key="${item.key}"
93
101
  label="${item.primaryText}"
94
102
  selectable>
95
- ${nested ? null : html`<img slot="illustration" src="${item.imgSrc}">`}
103
+ ${item.imgSrc.length === 0 ? null : html`<img slot="illustration" src="${item.imgSrc}">`}
96
104
  <d2l-list-item-content>
97
105
  <div>${item.primaryText}</div>
98
106
  <div slot="supporting-info">${item.supportingText}</div>
@@ -7,6 +7,7 @@ import { RtlMixin } from '../../mixins/rtl-mixin.js';
7
7
 
8
8
  /**
9
9
  * A header for list components containing select-all, etc.
10
+ * @slot - Responsive container using `d2l-overflow-group` for `d2l-selection-action` elements
10
11
  */
11
12
  class ListHeader extends RtlMixin(LocalizeCoreElement(LitElement)) {
12
13
 
@@ -6,6 +6,7 @@ import { LitElement } from 'lit-element/lit-element.js';
6
6
  * @slot - Default content placed inside of the component
7
7
  * @slot illustration - Image associated with the list item located at the left of the item
8
8
  * @slot actions - Actions (e.g., button icons) associated with the listen item located at the right of the item
9
+ * @slot nested - Nested d2l-list element
9
10
  */
10
11
  class ListItemButton extends ListItemButtonMixin(LitElement) {
11
12
 
@@ -25,7 +25,7 @@ export const ListItemCheckboxMixin = superclass => class extends SkeletonMixin(L
25
25
  */
26
26
  key: { type: String, reflect: true },
27
27
  /**
28
- * **Selection:** Indicates a input should be rendered for selecting the item
28
+ * **Selection:** Indicates an input should be rendered for selecting the item
29
29
  * @type {boolean}
30
30
  */
31
31
  selectable: { type: Boolean },
@@ -60,6 +60,8 @@ export const ListItemCheckboxMixin = superclass => class extends SkeletonMixin(L
60
60
 
61
61
  constructor() {
62
62
  super();
63
+ this.disabled = false;
64
+ this.selectable = false;
63
65
  this.selected = false;
64
66
  this.selectionInfo = new SelectionInfo();
65
67
  this._checkboxId = getUniqueId();
@@ -264,7 +264,7 @@ export const ListItemDragDropMixin = superclass => class extends superclass {
264
264
  */
265
265
  dragHandleText: { type: String, attribute: 'drag-handle-text' },
266
266
  /**
267
- * **Drag & drop:** Whether the items can be dropped as nested children
267
+ * **Drag & drop:** Whether nested items can be dropped on this item
268
268
  * @type {boolean}
269
269
  */
270
270
  dropNested: { type: Boolean, attribute: 'drop-nested' },
@@ -374,6 +374,7 @@ export const ListItemDragDropMixin = superclass => class extends superclass {
374
374
  _dispatchListItemsMove(sourceItems, targetItem, moveLocation, keyboardActive) {
375
375
  if (!keyboardActive) keyboardActive = false;
376
376
  const rootList = this._getRootList();
377
+ /** @ignore */
377
378
  rootList.dispatchEvent(new CustomEvent('d2l-list-items-move', {
378
379
  detail: {
379
380
  keyboardActive: keyboardActive,
@@ -6,6 +6,7 @@ import { LitElement } from 'lit-element/lit-element.js';
6
6
  * @slot - Default content placed inside of the component
7
7
  * @slot illustration - Image associated with the list item located at the left of the item
8
8
  * @slot actions - Actions (e.g., button icons) associated with the listen item located at the right of the item
9
+ * @slot nested - Nested d2l-list element
9
10
  */
10
11
  class ListItem extends ListItemLinkMixin(LitElement) {
11
12
 
@@ -10,17 +10,20 @@ export const listSelectionStates = SelectionInfo.states;
10
10
 
11
11
  /**
12
12
  * A container for a styled list of items ("d2l-list-item"). It provides the appropriate "list" semantics as well as options for displaying separators, etc.
13
- * @slot - List content (e.g., `listitem`s)
13
+ * @slot - Slot for list items (ex. `d2l-list-item`, `d2l-list-item-button`, or custom items)
14
+ * @slot header - Slot for `d2l-list-header` to be rendered above the list
15
+ * @fires d2l-list-items-move - Dispatched when one or more items are moved. See [Event Details: d2l-list-items-move](#event-details%3A-%40d2l-list-items-move).
14
16
  */
15
17
  class List extends SelectionMixin(LitElement) {
16
18
 
17
19
  static get properties() {
18
20
  return {
19
21
  /**
20
- * Whether to the user can drag multiple items
22
+ * Not publicly available yet. Whether the user can drag multiple items
21
23
  * @type {boolean}
22
- */
23
- dragMultiple: { type: Boolean, attribute: 'drag-multiple' },
24
+ * @ignore
25
+ */
26
+ dragMultiple: { type: Boolean, reflect: true, attribute: 'drag-multiple' },
24
27
  /**
25
28
  * Whether to extend the separators beyond the content's edge
26
29
  * @type {boolean}
@@ -0,0 +1,177 @@
1
+ # Subscriber Controllers
2
+
3
+ The `SubscriberRegistryController` and the corresponding `*SubscriberController`s can be used to create a subscription system within your app. Components can setup a subscriber registry instance to keep track of all components subscribed to them with the `SubscriberRegistryController`. Whenever it makes sense to do so, they can iterate over their subscribers to perform some action, update them with new data, etc. Components can subscribe themselves to different registries using the `IdSubscriberController` or the `EventSubscriberController`. This system supports a many-to-many relationship - registry components can contain multiple registry instances with multiple subscribers in each, and subscriber components can subscribe to multiple different registries.
4
+
5
+ ## Usage
6
+
7
+ Create an instance of the `SubscriberRegistryController` in the component that will be responsible for providing some data or performing some function on all its subscribers:
8
+
9
+ ```js
10
+ import { SubscriberRegistryController } from '@brightspace-ui/core/controllers/subscriber/subscriberControllers.js';
11
+
12
+ class CableSubscription extends LitElement {
13
+ constructor() {
14
+ super();
15
+ this._sportsSubscribers = new SubscriberRegistryController(this,
16
+ { onSubscribe: this._unlockSportsChannels.bind(this) },
17
+ { eventName: 'd2l-channels-subscribe-sports' }
18
+ );
19
+
20
+ this._movieSubscribers = new SubscriberRegistryController(this, {},
21
+ { onSubscribe: this._unlockMovieChannels.bind(this), updateSubscribers: this._sendMovieGuide.bind(this) },
22
+ { eventName: 'd2l-channels-subscribe-movies' }
23
+ );
24
+
25
+ // This controller only supports registering by id - no event is needed
26
+ this._kidsChannelSubscribers = new SubscriberRegistryController(this,
27
+ { onSubscribe: this._unlockKidsChannels.bind(this) }, {});
28
+ }
29
+
30
+ getController(controllerId) {
31
+ if (controllerId === 'sports') {
32
+ return this._sportsSubscribers;
33
+ } else if (controllerId === 'movies') {
34
+ return this._movieSubscribers;
35
+ } else if (controllerId === 'kids') {
36
+ return this._kidsChannelSubscribers;
37
+ }
38
+ }
39
+
40
+ _sendMovieGuide(subscribers) {
41
+ subscribers.forEach(subscriber => subscriber.updateGuide(new MovieGuide(new Date().getMonth())));
42
+ }
43
+
44
+ _unlockMovieChannels(subscriber) {
45
+ subscriber.addChannels([330, 331, 332, 333, 334, 335]);
46
+ }
47
+
48
+ ...
49
+ }
50
+ ```
51
+
52
+ When creating the controller, you can pass in callbacks to run whenever a subscriber is added, removed, or `updateSubscribers` is called (which handles request debouncing for you).
53
+
54
+ The `*subscriberController`s will use a `getController` method that needs to be exposed on the registry component. If you only have one `SubscriberRegistryController` you can simple return that. If you have multiple, you will return the proper controller depending on the id the subscriber component passed to you.
55
+
56
+ Once this has been set up, components can subscribe to particular registries two different ways:
57
+ 1. Using a matching event name with `EventSubscriberController`. The component will need to be a child of the registry component for this to work.
58
+ 2. By pointing to the registry component's id with `IdSubscriberController`. The component will need to be in the same DOM scope as the registry component for this to work.
59
+
60
+ Like the `SubscriberRegistryController`, these `*subscriberController`s take optional callbacks to throw at different points in the subscription process.
61
+
62
+ ```js
63
+ import { EventSubscriberController, IdSubscriberController } from '@brightspace-ui/core/controllers/subscriber/subscriberControllers.js';
64
+
65
+ class GeneralViewer extends LitElement {
66
+ static get properties() {
67
+ return {
68
+ _subscribedChannels: { type: Object }
69
+ };
70
+ }
71
+
72
+ constructor() {
73
+ super();
74
+ this._subscribedChannels = new Set();
75
+
76
+ this._sportsSubscription = new EventSubscriberController(this,
77
+ { onError: this._onSportsError.bind(this) }
78
+ { eventName: 'd2l-channels-subscribe-sports', controllerId: 'sports' }
79
+ );
80
+
81
+ this._movieSubscription = new EventSubscriberController(this, {},
82
+ { eventName: 'd2l-channels-subscribe-movies', controllerId: 'movies' }
83
+ );
84
+ }
85
+
86
+ addChannels(channels) {
87
+ channels.forEach(channel => this._subscribedChannels.add(channel));
88
+ }
89
+
90
+ _onSportsError() {
91
+ throw new Error('Where are the sports?');
92
+ }
93
+
94
+ ...
95
+ }
96
+
97
+ class YoungerViewer extends LitElement {
98
+ static get properties() {
99
+ return {
100
+ for: { type: String },
101
+ _subscribedChannels: { type: Object }
102
+ };
103
+ }
104
+
105
+ constructor() {
106
+ super();
107
+ this._subscribedChannels = new Set();
108
+
109
+ this._kidsSubscription = new IdSubscriberController(this,
110
+ { onSubscribe: this._onSubscribe.bind(this), onUnsubscribe: this._onUnsubscribe.bind(this) },
111
+ { idPropertyName: 'for', controllerId: 'kids' }
112
+ );
113
+ }
114
+
115
+ addChannels(channels) {
116
+ channels.forEach(channel => this._subscribedChannels.add(channel));
117
+ }
118
+
119
+ _onSubscribe(cableProvider) {
120
+ console.log(`Subscribed with ${cableProvider.id} successfully.`);
121
+ }
122
+
123
+ _onUnsubscribe(cableProviderId) {
124
+ console.log(`Looks like ${cableProviderId} is having an outage again.`);
125
+ }
126
+
127
+ ...
128
+ }
129
+ ```
130
+
131
+ An example of what this could look like altogether:
132
+ ```html
133
+ <cable-subscription id="rogers">
134
+ <general-viewer></general-viewer>
135
+ </cable-subscription>
136
+ <younger-viewer for="rogers"></younger-viewer>
137
+ ```
138
+
139
+ NOTE: Until we are on Lit 2, the controller lifecycle events will need to be manually called:
140
+ ```js
141
+ connectedCallback() {
142
+ super.connectedCallback();
143
+ if (this._subscriptionController) this._subscriptionController.hostConnected();
144
+ }
145
+
146
+ disconnectedCallback() {
147
+ super.disconnectedCallback();
148
+ if (this._subscriptionController) this._subscriptionController.hostDisconnected();
149
+ }
150
+
151
+ updated(changedProperties) {
152
+ super.updated(changedProperties);
153
+ if (this._subscriptionController) this._subscriptionController.hostUpdated(changedProperties);
154
+ }
155
+ ```
156
+
157
+ ## Available Callbacks
158
+
159
+ ### SubscriberRegistryController
160
+ | Callback Name | Description | Passed to Callback |
161
+ |---|---|---|
162
+ | `onSubscribe` | Runs whenever a new subscriber is added | Subscriber that was just subscribed |
163
+ | `onUnsubscribe` | Runs whenever a subscriber is removed | Subscriber that was just unsubscribed |
164
+ | `updateSubscribers` | Runs whenever `updateSubscribers` is called on the controller, handles debouncing requests for you | Map of all current subscribers |
165
+
166
+ ### EventSubscriberController
167
+ | Callback Name | Description | Passed to Callback |
168
+ |---|---|---|
169
+ | `onSubscribe` | Runs when successfully subscribed to a registry component | Registry that was just subscribed to |
170
+ | `onError` | Runs if the event was unacknowledged and no registry component was found | None |
171
+
172
+ ### IdSubscriberController
173
+ | Callback Name | Description | Passed to Callback |
174
+ |---|---|---|
175
+ | `onSubscribe` | Runs whenever a registry component is successfully subscribed to | Registry that was just subscribed to |
176
+ | `onUnsubscribe` | Runs whenever we unsubscribe to a registry (because it is now gone, or its id was removed from the id property list) | Id of the registry that was just unsubscribed to |
177
+ | `onError` | Runs if no registry component was found for an id | Id of the registry we do not have a component for |
@@ -0,0 +1,180 @@
1
+ import { cssEscape } from '../../helpers/dom.js';
2
+
3
+ export class SubscriberRegistryController {
4
+
5
+ constructor(host, callbacks, options) {
6
+ this._host = host;
7
+ this._callbacks = callbacks || {};
8
+ this._eventName = options && options.eventName;
9
+ this._subscribers = new Map();
10
+
11
+ this._handleSubscribe = this._handleSubscribe.bind(this);
12
+ }
13
+
14
+ get subscribers() {
15
+ return this._subscribers;
16
+ }
17
+
18
+ hostConnected() {
19
+ if (this._eventName) this._host.addEventListener(this._eventName, this._handleSubscribe);
20
+ }
21
+
22
+ hostDisconnected() {
23
+ if (this._eventName) this._host.removeEventListener(this._eventName, this._handleSubscribe);
24
+ }
25
+
26
+ subscribe(target) {
27
+ if (this._subscribers.has(target)) return;
28
+ this._subscribers.set(target, target);
29
+ if (this._callbacks.onSubscribe) this._callbacks.onSubscribe(target);
30
+ }
31
+
32
+ unsubscribe(target) {
33
+ this._subscribers.delete(target);
34
+ if (this._callbacks.onUnsubscribe) this._callbacks.onUnsubscribe(target);
35
+ }
36
+
37
+ updateSubscribers() {
38
+ if (!this._subscribers || this._subscribers.size === 0) return;
39
+ if (!this._callbacks.updateSubscribers) return;
40
+
41
+ // debounce the updates
42
+ if (this._updateSubscribersRequested) return;
43
+
44
+ this._updateSubscribersRequested = true;
45
+ setTimeout(() => {
46
+ this._callbacks.updateSubscribers(this._subscribers);
47
+ this._updateSubscribersRequested = false;
48
+ }, 0);
49
+ }
50
+
51
+ _handleSubscribe(e) {
52
+ e.stopPropagation();
53
+ e.detail.registry = this._host;
54
+ const target = e.composedPath()[0];
55
+ this.subscribe(target);
56
+ }
57
+ }
58
+
59
+ export class EventSubscriberController {
60
+
61
+ constructor(host, callbacks, options) {
62
+ this._host = host;
63
+ this._callbacks = callbacks || {};
64
+ this._eventName = options && options.eventName;
65
+ this._controllerId = options && options.controllerId;
66
+ this._registry = null;
67
+ }
68
+
69
+ get registry() {
70
+ return this._registry;
71
+ }
72
+
73
+ hostConnected() {
74
+ // delay subscription otherwise import/upgrade order can cause selection mixin to miss event
75
+ requestAnimationFrame(() => {
76
+ const evt = new CustomEvent(this._eventName, {
77
+ bubbles: true,
78
+ composed: true,
79
+ detail: {}
80
+ });
81
+ this._host.dispatchEvent(evt);
82
+ this._registry = evt.detail.registry;
83
+
84
+ if (!this._registry) {
85
+ if (this._callbacks.onError) this._callbacks.onError();
86
+ return;
87
+ }
88
+ if (this._callbacks.onSubscribe) this._callbacks.onSubscribe(this._registry);
89
+ });
90
+ }
91
+
92
+ hostDisconnected() {
93
+ if (this._registry) this._registry.getController(this._controllerId).unsubscribe(this._host);
94
+ }
95
+
96
+ }
97
+
98
+ export class IdSubscriberController {
99
+
100
+ constructor(host, callbacks, options) {
101
+ this._host = host;
102
+ this._callbacks = callbacks || {};
103
+ this._idPropertyName = options && options.idPropertyName;
104
+ this._controllerId = options && options.controllerId;
105
+ this._registries = new Map();
106
+ this._timeouts = new Set();
107
+ }
108
+
109
+ get registries() {
110
+ return Array.from(this._registries.values());
111
+ }
112
+
113
+ hostDisconnected() {
114
+ if (this._registryObserver) this._registryObserver.disconnect();
115
+ this._timeouts.forEach(timeoutId => clearTimeout(timeoutId));
116
+ this._registries.forEach(registry => {
117
+ registry.getController(this._controllerId).unsubscribe(this._host);
118
+ });
119
+ }
120
+
121
+ hostUpdated(changedProperties) {
122
+ if (!changedProperties.has(this._idPropertyName)) return;
123
+
124
+ if (this._registryObserver) this._registryObserver.disconnect();
125
+ this._registries.forEach(registry => {
126
+ registry.getController(this._controllerId).unsubscribe(this._host);
127
+ if (this._callbacks.onUnsubscribe) this._callbacks.onUnsubscribe(registry.id);
128
+ });
129
+ this._registries = new Map();
130
+
131
+ this._updateRegistries();
132
+
133
+ this._registryObserver = new MutationObserver(() => {
134
+ this._updateRegistries();
135
+ });
136
+
137
+ this._registryObserver.observe(this._host.getRootNode(), {
138
+ childList: true,
139
+ subtree: true
140
+ });
141
+ }
142
+
143
+ _updateRegistries() {
144
+ let registryIds = this._host[this._idPropertyName];
145
+ if (!registryIds) return;
146
+
147
+ registryIds = registryIds.split(' ');
148
+ registryIds.forEach(registryId => {
149
+ this._updateRegistry(registryId, 0);
150
+ });
151
+ }
152
+
153
+ _updateRegistry(registryId, elapsedTime) {
154
+ let registryComponent = this._host.getRootNode().querySelector(`#${cssEscape(registryId)}`);
155
+ if (!registryComponent && this._callbacks.onError) {
156
+ if (elapsedTime < 3000) {
157
+ const timeoutId = setTimeout(() => {
158
+ this._timeouts.delete(timeoutId);
159
+ this._updateRegistry(registryId, elapsedTime + 100);
160
+ }, 100);
161
+ this._timeouts.add(timeoutId);
162
+ } else {
163
+ this._callbacks.onError(registryId);
164
+ }
165
+ }
166
+
167
+ registryComponent = registryComponent || undefined;
168
+ if (this._registries.get(registryId) === registryComponent) return;
169
+
170
+ if (registryComponent) {
171
+ registryComponent.getController(this._controllerId).subscribe(this._host);
172
+ this._registries.set(registryId, registryComponent);
173
+ if (this._callbacks.onSubscribe) this._callbacks.onSubscribe(registryComponent);
174
+ } else {
175
+ this._registries.delete(registryId);
176
+ if (this._callbacks.onUnsubscribe) this._callbacks.onUnsubscribe(registryId);
177
+ }
178
+ }
179
+
180
+ }
@@ -6260,7 +6260,7 @@
6260
6260
  {
6261
6261
  "name": "items",
6262
6262
  "type": "array",
6263
- "default": "[{\"key\":\"1\",\"primaryText\":\"Introductory Earth Sciences\",\"supportingText\":\"This course explores the geological processes of the Earth's interior and surface. These include volcanism, earthquakes, mountain building, glaciation and weathering.\",\"imgSrc\":\"https://s.brightspace.com/course-images/images/63b162ab-b582-4bf9-8c1d-1dad04714121/tile-high-density-max-size.jpg\",\"items\":[{\"key\":\"1-1\",\"primaryText\":\"Glaciation\",\"supportingText\":\"Supporting Info\",\"imgSrc\":\"\",\"items\":[]},{\"key\":\"1-2\",\"primaryText\":\"Weathering\",\"supportingText\":\"Supporting Info\",\"imgSrc\":\"\",\"items\":[]},{\"key\":\"1-3\",\"primaryText\":\"Volcanism\",\"supportingText\":\"Supporting Info\",\"imgSrc\":\"\",\"items\":[]}]},{\"key\":\"2\",\"primaryText\":\"Flow and Transport Through Fractured Rocks\",\"supportingText\":\"Fractures are ubiquitous in geologic media and important in disciplines such as physical and contaminant hydrogeology, geotechnical engineering, civil and environmental engineering, petroleum engineering among other areas.\",\"imgSrc\":\"https://s.brightspace.com/course-images/images/e5fd575a-bc14-4a80-89e1-46f349a76178/tile-high-density-max-size.jpg\",\"items\":[{\"key\":\"2-1\",\"primaryText\":\"Contaminant Transport\",\"supportingText\":\"Supporting Info\",\"imgSrc\":\"\",\"items\":[]},{\"key\":\"2-2\",\"primaryText\":\"Modelling Flow in Fractured Media\",\"supportingText\":\"Supporting Info\",\"imgSrc\":\"\",\"items\":[]}]},{\"key\":\"3\",\"primaryText\":\"Applied Wetland Science\",\"supportingText\":\"Advanced concepts on wetland ecosystems in the context of regional and global earth systems processes such as carbon and nitrogen cycling and climate change, applications of wetland paleoecology, use of isotopes and other geochemical tools in wetland science, and wetland engineering in landscape rehabilitation and ecotechnology.\",\"imgSrc\":\"https://s.brightspace.com/course-images/images/38e839b1-37fa-470c-8830-b189ce4ae134/tile-high-density-max-size.jpg\",\"items\":[{\"key\":\"3-1\",\"primaryText\":\"Carbon & Nitrogen Cycling\",\"supportingText\":\"Supporting Info\",\"imgSrc\":\"\",\"items\":[]},{\"key\":\"3-2\",\"primaryText\":\"Wetland Engineering\",\"supportingText\":\"Supporting Info\",\"imgSrc\":\"\",\"items\":[]}]}]"
6263
+ "default": "[{\"key\":\"1\",\"primaryText\":\"Introductory Earth Sciences\",\"supportingText\":\"This course explores the geological processes of the Earth's interior and surface. These include volcanism, earthquakes, mountain building, glaciation and weathering.\",\"imgSrc\":\"https://s.brightspace.com/course-images/images/63b162ab-b582-4bf9-8c1d-1dad04714121/tile-high-density-max-size.jpg\",\"dropNested\":true,\"items\":[{\"key\":\"1-1\",\"primaryText\":\"Glaciation\",\"supportingText\":\"Nesting Allowed\",\"imgSrc\":\"https://s.brightspace.com/course-images/images/bf648978-6637-4fdc-815b-81572c436c0e/tile-high-density-max-size.jpg\",\"dropNested\":true,\"items\":[]},{\"key\":\"1-2\",\"primaryText\":\"Weathering\",\"supportingText\":\"Nesting Allowed\",\"imgSrc\":\"https://s.brightspace.com/course-images/images/50f91ba6-7c25-482a-bd71-1c4b7c8d2154/tile-high-density-min-size.jpg\",\"dropNested\":true,\"items\":[]},{\"key\":\"1-3\",\"primaryText\":\"Volcanism\",\"supportingText\":\"Nesting Allowed\",\"imgSrc\":\"https://s.brightspace.com/course-images/images/5eb2371d-6099-4c8d-8aad-075f357012a2/tile-high-density-min-size.jpg\",\"dropNested\":true,\"items\":[]}]},{\"key\":\"2\",\"primaryText\":\"Flow and Transport Through Fractured Rocks\",\"supportingText\":\"Fractures are ubiquitous in geologic media and important in disciplines such as physical and contaminant hydrogeology, geotechnical engineering, civil and environmental engineering, petroleum engineering among other areas.\",\"imgSrc\":\"https://s.brightspace.com/course-images/images/e5fd575a-bc14-4a80-89e1-46f349a76178/tile-high-density-max-size.jpg\",\"items\":[{\"key\":\"2-1\",\"primaryText\":\"Contaminant Transport\",\"supportingText\":\"No Nesting Allowed\",\"imgSrc\":\"https://s.brightspace.com/course-images/images/824fffa1-86a6-4489-84ba-91edfbc1dcc4/tile-high-density-min-size.jpg\",\"dropNested\":false,\"items\":[]},{\"key\":\"2-2\",\"primaryText\":\"Modelling Flow in Fractured Media\",\"supportingText\":\"No Nesting Allowed\",\"imgSrc\":\"https://s.brightspace.com/course-images/images/e18c92a4-b996-444f-84b5-988874feccac/tile-high-density-min-size.jpg\",\"dropNested\":false,\"items\":[]}]},{\"key\":\"3\",\"primaryText\":\"Applied Wetland Science\",\"supportingText\":\"Advanced concepts on wetland ecosystems in the context of regional and global earth systems processes such as carbon and nitrogen cycling and climate change, applications of wetland paleoecology, use of isotopes and other geochemical tools in wetland science, and wetland engineering in landscape rehabilitation and ecotechnology.\",\"imgSrc\":\"https://s.brightspace.com/course-images/images/38e839b1-37fa-470c-8830-b189ce4ae134/tile-high-density-max-size.jpg\",\"items\":[{\"key\":\"3-1\",\"primaryText\":\"Carbon & Nitrogen Cycling\",\"supportingText\":\"Nesting Allowed\",\"imgSrc\":\"https://s.brightspace.com/course-images/images/623b420b-a305-4762-8af8-598f0e72e956/tile-high-density-min-size.jpg\",\"dropNested\":true,\"items\":[]},{\"key\":\"3-2\",\"primaryText\":\"Wetland Engineering\",\"supportingText\":\"Nesting Allowed\",\"imgSrc\":\"https://s.brightspace.com/course-images/images/26102577-8f2a-4e24-84b5-19d76decbc7a/tile-high-density-min-size.jpg\",\"dropNested\":true,\"items\":[]}]}]"
6264
6264
  }
6265
6265
  ],
6266
6266
  "properties": [
@@ -6268,7 +6268,7 @@
6268
6268
  "name": "items",
6269
6269
  "attribute": "items",
6270
6270
  "type": "array",
6271
- "default": "[{\"key\":\"1\",\"primaryText\":\"Introductory Earth Sciences\",\"supportingText\":\"This course explores the geological processes of the Earth's interior and surface. These include volcanism, earthquakes, mountain building, glaciation and weathering.\",\"imgSrc\":\"https://s.brightspace.com/course-images/images/63b162ab-b582-4bf9-8c1d-1dad04714121/tile-high-density-max-size.jpg\",\"items\":[{\"key\":\"1-1\",\"primaryText\":\"Glaciation\",\"supportingText\":\"Supporting Info\",\"imgSrc\":\"\",\"items\":[]},{\"key\":\"1-2\",\"primaryText\":\"Weathering\",\"supportingText\":\"Supporting Info\",\"imgSrc\":\"\",\"items\":[]},{\"key\":\"1-3\",\"primaryText\":\"Volcanism\",\"supportingText\":\"Supporting Info\",\"imgSrc\":\"\",\"items\":[]}]},{\"key\":\"2\",\"primaryText\":\"Flow and Transport Through Fractured Rocks\",\"supportingText\":\"Fractures are ubiquitous in geologic media and important in disciplines such as physical and contaminant hydrogeology, geotechnical engineering, civil and environmental engineering, petroleum engineering among other areas.\",\"imgSrc\":\"https://s.brightspace.com/course-images/images/e5fd575a-bc14-4a80-89e1-46f349a76178/tile-high-density-max-size.jpg\",\"items\":[{\"key\":\"2-1\",\"primaryText\":\"Contaminant Transport\",\"supportingText\":\"Supporting Info\",\"imgSrc\":\"\",\"items\":[]},{\"key\":\"2-2\",\"primaryText\":\"Modelling Flow in Fractured Media\",\"supportingText\":\"Supporting Info\",\"imgSrc\":\"\",\"items\":[]}]},{\"key\":\"3\",\"primaryText\":\"Applied Wetland Science\",\"supportingText\":\"Advanced concepts on wetland ecosystems in the context of regional and global earth systems processes such as carbon and nitrogen cycling and climate change, applications of wetland paleoecology, use of isotopes and other geochemical tools in wetland science, and wetland engineering in landscape rehabilitation and ecotechnology.\",\"imgSrc\":\"https://s.brightspace.com/course-images/images/38e839b1-37fa-470c-8830-b189ce4ae134/tile-high-density-max-size.jpg\",\"items\":[{\"key\":\"3-1\",\"primaryText\":\"Carbon & Nitrogen Cycling\",\"supportingText\":\"Supporting Info\",\"imgSrc\":\"\",\"items\":[]},{\"key\":\"3-2\",\"primaryText\":\"Wetland Engineering\",\"supportingText\":\"Supporting Info\",\"imgSrc\":\"\",\"items\":[]}]}]"
6271
+ "default": "[{\"key\":\"1\",\"primaryText\":\"Introductory Earth Sciences\",\"supportingText\":\"This course explores the geological processes of the Earth's interior and surface. These include volcanism, earthquakes, mountain building, glaciation and weathering.\",\"imgSrc\":\"https://s.brightspace.com/course-images/images/63b162ab-b582-4bf9-8c1d-1dad04714121/tile-high-density-max-size.jpg\",\"dropNested\":true,\"items\":[{\"key\":\"1-1\",\"primaryText\":\"Glaciation\",\"supportingText\":\"Nesting Allowed\",\"imgSrc\":\"https://s.brightspace.com/course-images/images/bf648978-6637-4fdc-815b-81572c436c0e/tile-high-density-max-size.jpg\",\"dropNested\":true,\"items\":[]},{\"key\":\"1-2\",\"primaryText\":\"Weathering\",\"supportingText\":\"Nesting Allowed\",\"imgSrc\":\"https://s.brightspace.com/course-images/images/50f91ba6-7c25-482a-bd71-1c4b7c8d2154/tile-high-density-min-size.jpg\",\"dropNested\":true,\"items\":[]},{\"key\":\"1-3\",\"primaryText\":\"Volcanism\",\"supportingText\":\"Nesting Allowed\",\"imgSrc\":\"https://s.brightspace.com/course-images/images/5eb2371d-6099-4c8d-8aad-075f357012a2/tile-high-density-min-size.jpg\",\"dropNested\":true,\"items\":[]}]},{\"key\":\"2\",\"primaryText\":\"Flow and Transport Through Fractured Rocks\",\"supportingText\":\"Fractures are ubiquitous in geologic media and important in disciplines such as physical and contaminant hydrogeology, geotechnical engineering, civil and environmental engineering, petroleum engineering among other areas.\",\"imgSrc\":\"https://s.brightspace.com/course-images/images/e5fd575a-bc14-4a80-89e1-46f349a76178/tile-high-density-max-size.jpg\",\"items\":[{\"key\":\"2-1\",\"primaryText\":\"Contaminant Transport\",\"supportingText\":\"No Nesting Allowed\",\"imgSrc\":\"https://s.brightspace.com/course-images/images/824fffa1-86a6-4489-84ba-91edfbc1dcc4/tile-high-density-min-size.jpg\",\"dropNested\":false,\"items\":[]},{\"key\":\"2-2\",\"primaryText\":\"Modelling Flow in Fractured Media\",\"supportingText\":\"No Nesting Allowed\",\"imgSrc\":\"https://s.brightspace.com/course-images/images/e18c92a4-b996-444f-84b5-988874feccac/tile-high-density-min-size.jpg\",\"dropNested\":false,\"items\":[]}]},{\"key\":\"3\",\"primaryText\":\"Applied Wetland Science\",\"supportingText\":\"Advanced concepts on wetland ecosystems in the context of regional and global earth systems processes such as carbon and nitrogen cycling and climate change, applications of wetland paleoecology, use of isotopes and other geochemical tools in wetland science, and wetland engineering in landscape rehabilitation and ecotechnology.\",\"imgSrc\":\"https://s.brightspace.com/course-images/images/38e839b1-37fa-470c-8830-b189ce4ae134/tile-high-density-max-size.jpg\",\"items\":[{\"key\":\"3-1\",\"primaryText\":\"Carbon & Nitrogen Cycling\",\"supportingText\":\"Nesting Allowed\",\"imgSrc\":\"https://s.brightspace.com/course-images/images/623b420b-a305-4762-8af8-598f0e72e956/tile-high-density-min-size.jpg\",\"dropNested\":true,\"items\":[]},{\"key\":\"3-2\",\"primaryText\":\"Wetland Engineering\",\"supportingText\":\"Nesting Allowed\",\"imgSrc\":\"https://s.brightspace.com/course-images/images/26102577-8f2a-4e24-84b5-19d76decbc7a/tile-high-density-min-size.jpg\",\"dropNested\":true,\"items\":[]}]}]"
6272
6272
  }
6273
6273
  ]
6274
6274
  },
@@ -6306,23 +6306,24 @@
6306
6306
  },
6307
6307
  {
6308
6308
  "name": "drop-nested",
6309
- "description": "**Drag & drop:** Whether the items can be dropped as nested children",
6309
+ "description": "**Drag & drop:** Whether nested items can be dropped on this item",
6310
6310
  "type": "boolean",
6311
6311
  "default": "false"
6312
6312
  },
6313
- {
6314
- "name": "disabled",
6315
- "description": "**Selection:** Disables the input",
6316
- "type": "boolean"
6317
- },
6318
6313
  {
6319
6314
  "name": "key",
6320
6315
  "description": "Value to identify item if selectable",
6321
6316
  "type": "string"
6322
6317
  },
6318
+ {
6319
+ "name": "disabled",
6320
+ "description": "**Selection:** Disables the input",
6321
+ "type": "boolean",
6322
+ "default": "false"
6323
+ },
6323
6324
  {
6324
6325
  "name": "selectable",
6325
- "description": "**Selection:** Indicates a input should be rendered for selecting the item",
6326
+ "description": "**Selection:** Indicates an input should be rendered for selecting the item",
6326
6327
  "type": "boolean",
6327
6328
  "default": "true"
6328
6329
  },
@@ -6386,26 +6387,27 @@
6386
6387
  {
6387
6388
  "name": "dropNested",
6388
6389
  "attribute": "drop-nested",
6389
- "description": "**Drag & drop:** Whether the items can be dropped as nested children",
6390
+ "description": "**Drag & drop:** Whether nested items can be dropped on this item",
6390
6391
  "type": "boolean",
6391
6392
  "default": "false"
6392
6393
  },
6393
- {
6394
- "name": "disabled",
6395
- "attribute": "disabled",
6396
- "description": "**Selection:** Disables the input",
6397
- "type": "boolean"
6398
- },
6399
6394
  {
6400
6395
  "name": "key",
6401
6396
  "attribute": "key",
6402
6397
  "description": "Value to identify item if selectable",
6403
6398
  "type": "string"
6404
6399
  },
6400
+ {
6401
+ "name": "disabled",
6402
+ "attribute": "disabled",
6403
+ "description": "**Selection:** Disables the input",
6404
+ "type": "boolean",
6405
+ "default": "false"
6406
+ },
6405
6407
  {
6406
6408
  "name": "selectable",
6407
6409
  "attribute": "selectable",
6408
- "description": "**Selection:** Indicates a input should be rendered for selecting the item",
6410
+ "description": "**Selection:** Indicates an input should be rendered for selecting the item",
6409
6411
  "type": "boolean",
6410
6412
  "default": "true"
6411
6413
  },
@@ -6449,9 +6451,6 @@
6449
6451
  "name": "d2l-list-item-position-change",
6450
6452
  "description": "Dispatched when a draggable list item's position changes in the list. See [Event Details: d2l-list-item-position-change](#event-details%3A-d2l-list-item-position-change)."
6451
6453
  },
6452
- {
6453
- "name": "d2l-list-items-move"
6454
- },
6455
6454
  {
6456
6455
  "name": "d2l-list-item-selected",
6457
6456
  "description": "Dispatched when the component item is selected"
@@ -6478,6 +6477,12 @@
6478
6477
  "type": "boolean",
6479
6478
  "default": "false"
6480
6479
  }
6480
+ ],
6481
+ "slots": [
6482
+ {
6483
+ "name": "",
6484
+ "description": "Responsive container using `d2l-overflow-group` for `d2l-selection-action` elements"
6485
+ }
6481
6486
  ]
6482
6487
  },
6483
6488
  {
@@ -6515,24 +6520,26 @@
6515
6520
  },
6516
6521
  {
6517
6522
  "name": "drop-nested",
6518
- "description": "**Drag & drop:** Whether the items can be dropped as nested children",
6523
+ "description": "**Drag & drop:** Whether nested items can be dropped on this item",
6519
6524
  "type": "boolean",
6520
6525
  "default": "false"
6521
6526
  },
6522
- {
6523
- "name": "disabled",
6524
- "description": "**Selection:** Disables the input",
6525
- "type": "boolean"
6526
- },
6527
6527
  {
6528
6528
  "name": "key",
6529
6529
  "description": "Value to identify item if selectable",
6530
6530
  "type": "string"
6531
6531
  },
6532
+ {
6533
+ "name": "disabled",
6534
+ "description": "**Selection:** Disables the input",
6535
+ "type": "boolean",
6536
+ "default": "false"
6537
+ },
6532
6538
  {
6533
6539
  "name": "selectable",
6534
- "description": "**Selection:** Indicates a input should be rendered for selecting the item",
6535
- "type": "boolean"
6540
+ "description": "**Selection:** Indicates an input should be rendered for selecting the item",
6541
+ "type": "boolean",
6542
+ "default": "false"
6536
6543
  },
6537
6544
  {
6538
6545
  "name": "selected",
@@ -6594,27 +6601,29 @@
6594
6601
  {
6595
6602
  "name": "dropNested",
6596
6603
  "attribute": "drop-nested",
6597
- "description": "**Drag & drop:** Whether the items can be dropped as nested children",
6604
+ "description": "**Drag & drop:** Whether nested items can be dropped on this item",
6598
6605
  "type": "boolean",
6599
6606
  "default": "false"
6600
6607
  },
6601
- {
6602
- "name": "disabled",
6603
- "attribute": "disabled",
6604
- "description": "**Selection:** Disables the input",
6605
- "type": "boolean"
6606
- },
6607
6608
  {
6608
6609
  "name": "key",
6609
6610
  "attribute": "key",
6610
6611
  "description": "Value to identify item if selectable",
6611
6612
  "type": "string"
6612
6613
  },
6614
+ {
6615
+ "name": "disabled",
6616
+ "attribute": "disabled",
6617
+ "description": "**Selection:** Disables the input",
6618
+ "type": "boolean",
6619
+ "default": "false"
6620
+ },
6613
6621
  {
6614
6622
  "name": "selectable",
6615
6623
  "attribute": "selectable",
6616
- "description": "**Selection:** Indicates a input should be rendered for selecting the item",
6617
- "type": "boolean"
6624
+ "description": "**Selection:** Indicates an input should be rendered for selecting the item",
6625
+ "type": "boolean",
6626
+ "default": "false"
6618
6627
  },
6619
6628
  {
6620
6629
  "name": "selected",
@@ -6660,9 +6669,6 @@
6660
6669
  "name": "d2l-list-item-position-change",
6661
6670
  "description": "Dispatched when a draggable list item's position changes in the list. See [Event Details: d2l-list-item-position-change](#event-details%3A-d2l-list-item-position-change)."
6662
6671
  },
6663
- {
6664
- "name": "d2l-list-items-move"
6665
- },
6666
6672
  {
6667
6673
  "name": "d2l-list-item-selected",
6668
6674
  "description": "Dispatched when the component item is selected"
@@ -6680,6 +6686,10 @@
6680
6686
  {
6681
6687
  "name": "actions",
6682
6688
  "description": "Actions (e.g., button icons) associated with the listen item located at the right of the item"
6689
+ },
6690
+ {
6691
+ "name": "nested",
6692
+ "description": "Nested d2l-list element"
6683
6693
  }
6684
6694
  ]
6685
6695
  },
@@ -6850,24 +6860,26 @@
6850
6860
  },
6851
6861
  {
6852
6862
  "name": "drop-nested",
6853
- "description": "**Drag & drop:** Whether the items can be dropped as nested children",
6863
+ "description": "**Drag & drop:** Whether nested items can be dropped on this item",
6854
6864
  "type": "boolean",
6855
6865
  "default": "false"
6856
6866
  },
6857
- {
6858
- "name": "disabled",
6859
- "description": "**Selection:** Disables the input",
6860
- "type": "boolean"
6861
- },
6862
6867
  {
6863
6868
  "name": "key",
6864
6869
  "description": "Value to identify item if selectable",
6865
6870
  "type": "string"
6866
6871
  },
6872
+ {
6873
+ "name": "disabled",
6874
+ "description": "**Selection:** Disables the input",
6875
+ "type": "boolean",
6876
+ "default": "false"
6877
+ },
6867
6878
  {
6868
6879
  "name": "selectable",
6869
- "description": "**Selection:** Indicates a input should be rendered for selecting the item",
6870
- "type": "boolean"
6880
+ "description": "**Selection:** Indicates an input should be rendered for selecting the item",
6881
+ "type": "boolean",
6882
+ "default": "false"
6871
6883
  },
6872
6884
  {
6873
6885
  "name": "selected",
@@ -6941,27 +6953,29 @@
6941
6953
  {
6942
6954
  "name": "dropNested",
6943
6955
  "attribute": "drop-nested",
6944
- "description": "**Drag & drop:** Whether the items can be dropped as nested children",
6956
+ "description": "**Drag & drop:** Whether nested items can be dropped on this item",
6945
6957
  "type": "boolean",
6946
6958
  "default": "false"
6947
6959
  },
6948
- {
6949
- "name": "disabled",
6950
- "attribute": "disabled",
6951
- "description": "**Selection:** Disables the input",
6952
- "type": "boolean"
6953
- },
6954
6960
  {
6955
6961
  "name": "key",
6956
6962
  "attribute": "key",
6957
6963
  "description": "Value to identify item if selectable",
6958
6964
  "type": "string"
6959
6965
  },
6966
+ {
6967
+ "name": "disabled",
6968
+ "attribute": "disabled",
6969
+ "description": "**Selection:** Disables the input",
6970
+ "type": "boolean",
6971
+ "default": "false"
6972
+ },
6960
6973
  {
6961
6974
  "name": "selectable",
6962
6975
  "attribute": "selectable",
6963
- "description": "**Selection:** Indicates a input should be rendered for selecting the item",
6964
- "type": "boolean"
6976
+ "description": "**Selection:** Indicates an input should be rendered for selecting the item",
6977
+ "type": "boolean",
6978
+ "default": "false"
6965
6979
  },
6966
6980
  {
6967
6981
  "name": "selected",
@@ -7007,9 +7021,6 @@
7007
7021
  "name": "d2l-list-item-position-change",
7008
7022
  "description": "Dispatched when a draggable list item's position changes in the list. See [Event Details: d2l-list-item-position-change](#event-details%3A-d2l-list-item-position-change)."
7009
7023
  },
7010
- {
7011
- "name": "d2l-list-items-move"
7012
- },
7013
7024
  {
7014
7025
  "name": "d2l-list-item-selected",
7015
7026
  "description": "Dispatched when the component item is selected"
@@ -7027,6 +7038,10 @@
7027
7038
  {
7028
7039
  "name": "actions",
7029
7040
  "description": "Actions (e.g., button icons) associated with the listen item located at the right of the item"
7041
+ },
7042
+ {
7043
+ "name": "nested",
7044
+ "description": "Nested d2l-list element"
7030
7045
  }
7031
7046
  ]
7032
7047
  },
@@ -7041,12 +7056,6 @@
7041
7056
  "type": "'all'|'between'|'none'",
7042
7057
  "default": "\"\\\"all\\\"\""
7043
7058
  },
7044
- {
7045
- "name": "drag-multiple",
7046
- "description": "Whether to the user can drag multiple items",
7047
- "type": "boolean",
7048
- "default": "false"
7049
- },
7050
7059
  {
7051
7060
  "name": "extend-separators",
7052
7061
  "description": "Whether to extend the separators beyond the content's edge",
@@ -7076,8 +7085,6 @@
7076
7085
  },
7077
7086
  {
7078
7087
  "name": "dragMultiple",
7079
- "attribute": "drag-multiple",
7080
- "description": "Whether to the user can drag multiple items",
7081
7088
  "type": "boolean",
7082
7089
  "default": "false"
7083
7090
  },
@@ -7104,6 +7111,10 @@
7104
7111
  }
7105
7112
  ],
7106
7113
  "events": [
7114
+ {
7115
+ "name": "d2l-list-items-move",
7116
+ "description": "Dispatched when one or more items are moved. See [Event Details: d2l-list-items-move](#event-details%3A-%40d2l-list-items-move)."
7117
+ },
7107
7118
  {
7108
7119
  "name": "d2l-list-selection-changes",
7109
7120
  "description": "Dispatched once for a set of selection state changes (ex. select-all); event detail includes an array of objects where each object contains the `key` and `selected` state for each changed item"
@@ -7116,7 +7127,11 @@
7116
7127
  "slots": [
7117
7128
  {
7118
7129
  "name": "",
7119
- "description": "List content (e.g., `listitem`s)"
7130
+ "description": "Slot for list items (ex. `d2l-list-item`, `d2l-list-item-button`, or custom items)"
7131
+ },
7132
+ {
7133
+ "name": "header",
7134
+ "description": "Slot for `d2l-list-header` to be rendered above the list"
7120
7135
  }
7121
7136
  ]
7122
7137
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brightspace-ui/core",
3
- "version": "1.211.0",
3
+ "version": "1.213.2",
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",
@@ -14,7 +14,7 @@
14
14
  "build": "npm run build:clean && npm run build:icons && npm run build:sass",
15
15
  "lint": "npm run lint:eslint && npm run lint:style && npm run lint:lit",
16
16
  "lint:eslint": "eslint . --ext .js,.html",
17
- "lint:lit": "lit-analyzer \"{components,directives,helpers,mixins,templates,test,tools}/**/*.js\" --strict",
17
+ "lint:lit": "lit-analyzer \"{components,controllers,directives,helpers,mixins,templates,test,tools}/**/*.js\" --strict",
18
18
  "lint:style": "stylelint \"**/*.{js,html}\"",
19
19
  "start": "web-dev-server --node-resolve --watch --open",
20
20
  "test": "npm run lint && npm run test:headless && npm run test:axe",
@@ -26,6 +26,7 @@
26
26
  "files": [
27
27
  "custom-elements.json",
28
28
  "/components",
29
+ "/controllers",
29
30
  "/directives",
30
31
  "/generated",
31
32
  "/helpers",
@@ -47,10 +48,10 @@
47
48
  "@open-wc/testing": "^2",
48
49
  "@web/dev-server": "^0.1",
49
50
  "@web/test-runner": "^0.13",
50
- "@web/test-runner-playwright": "^0.8.8",
51
+ "@web/test-runner-playwright": "^0.8",
51
52
  "axe-core": "^4",
52
53
  "chalk": "^5",
53
- "eslint": "^7",
54
+ "eslint": "^8",
54
55
  "eslint-config-brightspace": "^0.16",
55
56
  "eslint-plugin-html": "^6",
56
57
  "eslint-plugin-import": "^2",
@@ -60,7 +61,7 @@
60
61
  "node-sass": "^7",
61
62
  "sinon": "^12",
62
63
  "stylelint": "^14",
63
- "web-test-runner-performance": "^0.1.4"
64
+ "web-test-runner-performance": "^0.1"
64
65
  },
65
66
  "dependencies": {
66
67
  "@brightspace-ui/intl": "^3",
@@ -70,7 +71,7 @@
70
71
  "ifrau": "^0.39",
71
72
  "intl-messageformat": "^7",
72
73
  "lit-element": "^2",
73
- "lit-html": "^1.4.1",
74
+ "lit-html": "^1",
74
75
  "prismjs": "^1",
75
76
  "resize-observer-polyfill": "^1"
76
77
  }