@brightspace-ui/core 1.196.1 → 1.197.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.
Files changed (54) hide show
  1. package/components/backdrop/README.md +5 -6
  2. package/components/backdrop/backdrop.js +3 -0
  3. package/components/breadcrumbs/breadcrumbs.js +2 -1
  4. package/components/button/button-icon.js +1 -0
  5. package/components/button/button-mixin.js +2 -0
  6. package/components/button/button-subtle.js +1 -0
  7. package/components/button/button.js +1 -0
  8. package/components/button/floating-buttons.js +1 -0
  9. package/components/calendar/calendar.js +1 -1
  10. package/components/card/card-footer-link.js +12 -2
  11. package/components/card/card-loading-shimmer.js +1 -0
  12. package/components/card/card.js +9 -0
  13. package/components/dialog/dialog-confirm.js +1 -2
  14. package/components/dialog/dialog-fullscreen.js +4 -5
  15. package/components/dialog/dialog-mixin.js +2 -0
  16. package/components/dialog/dialog.js +0 -2
  17. package/components/dropdown/dropdown-button-subtle.js +3 -3
  18. package/components/dropdown/dropdown-button.js +2 -0
  19. package/components/dropdown/dropdown-content-mixin.js +19 -0
  20. package/components/dropdown/dropdown-content.js +0 -3
  21. package/components/dropdown/dropdown-context-menu.js +2 -0
  22. package/components/dropdown/dropdown-menu.js +0 -3
  23. package/components/dropdown/dropdown-more.js +2 -0
  24. package/components/dropdown/dropdown-opener-mixin.js +2 -0
  25. package/components/dropdown/dropdown-tabs.js +0 -3
  26. package/components/filter/filter-dimension-set-value.js +3 -0
  27. package/components/filter/filter-dimension-set.js +5 -1
  28. package/components/form/form-mixin.js +1 -0
  29. package/components/form/form-native.js +0 -1
  30. package/components/form/form.js +0 -1
  31. package/components/icons/images/tier3/rubric-graded.svg +2 -2
  32. package/components/inputs/input-date-range.js +9 -1
  33. package/components/inputs/input-date-time-range-to.js +3 -0
  34. package/components/inputs/input-date-time-range.js +10 -1
  35. package/components/inputs/input-date-time.js +7 -1
  36. package/components/inputs/input-date.js +7 -1
  37. package/components/inputs/input-fieldset.js +3 -0
  38. package/components/inputs/input-radio-styles.js +2 -1
  39. package/components/inputs/input-time-range.js +10 -1
  40. package/components/inputs/input-time.js +6 -1
  41. package/components/link/README.md +1 -1
  42. package/components/list/README.md +11 -10
  43. package/components/list/demo/list-item-custom.js +7 -3
  44. package/components/list/demo/list-nested.html +6 -62
  45. package/components/list/list-item-generic-layout.js +85 -14
  46. package/components/list/list.js +27 -2
  47. package/components/selection/selection-input.js +4 -2
  48. package/components/selection/selection-mixin.js +1 -0
  49. package/components/switch/switch-mixin.js +1 -0
  50. package/custom-elements.json +47 -90
  51. package/generated/icons/tier3/rubric-graded.js +3 -2
  52. package/helpers/focus.js +4 -2
  53. package/mixins/labelled-mixin.js +1 -0
  54. package/package.json +1 -1
@@ -23,13 +23,13 @@
23
23
  </head>
24
24
  <body unresolved>
25
25
 
26
- <d2l-demo-page page-title="d2l-list-item (nested)">
26
+ <d2l-demo-page page-title="d2l-list (nested)">
27
27
 
28
28
  <h2>Nested</h2>
29
29
 
30
30
  <d2l-demo-snippet>
31
31
  <template>
32
- <d2l-list>
32
+ <d2l-list grid>
33
33
  <d2l-list-header slot="header">
34
34
  <d2l-selection-action icon="tier1:bookmark-hollow" text="Bookmark" requires-selection></d2l-selection-action>
35
35
  <d2l-selection-action icon="tier1:gear" text="Settings"></d2l-selection-action>
@@ -39,80 +39,24 @@
39
39
  <div>Earth Sciences (L1)</div>
40
40
  <div slot="supporting-info">Earth science or geoscience includes all fields of natural science related to planet Earth. This is a branch of science dealing with the physical and chemical constitution of Earth and its atmosphere. Earth science can be considered to be a branch of planetary science, but with a much older history.</div>
41
41
  </d2l-list-item-content>
42
- <d2l-list slot="nested" separators="all">
42
+ <d2l-list slot="nested" grid separators="all">
43
43
  <d2l-list-item selectable key="L2-1" label="Label for L2-1">
44
44
  <d2l-list-item-content>
45
45
  <div>Introductory Earth Sciences (L2)</div>
46
46
  <div slot="supporting-info">This course explores the geological processes of the Earth's interior and surface. These include volcanism, earthquakes, mountain building, glaciation and weathering. Students will gain an appreciation of how these processes have controlled the evolution of our planet and the role of geology in meeting society's current and future demand for sustainable energy and mineral resources.</div>
47
47
  </d2l-list-item-content>
48
- <d2l-list slot="nested" separators="all">
48
+ <d2l-list slot="nested" grid separators="all">
49
49
  <d2l-list-item selectable key="L3-1" label="Label for L3-1">
50
50
  <d2l-list-item-content>
51
51
  <div>Glaciation (L3)</div>
52
52
  <div slot="supporting-info">Supporting Info</div>
53
53
  </d2l-list-item-content>
54
- <d2l-list slot="nested" separators="all">
54
+ <d2l-list slot="nested" grid separators="all">
55
55
  <d2l-list-item selectable key="L4-1" label="Label for L4-1">
56
56
  <d2l-list-item-content>
57
57
  <div>Ice Sheets (L4)</div>
58
58
  <div slot="supporting-info">Supporting Info</div>
59
59
  </d2l-list-item-content>
60
- <d2l-list slot="nested" separators="all">
61
- <d2l-list-item selectable key="L5-1" label="Label for L5-1">
62
- <d2l-list-item-content>
63
- <div>Topic 1 (L5)</div>
64
- <div slot="supporting-info">Supporting Info</div>
65
- </d2l-list-item-content>
66
- </d2l-list-item>
67
- <d2l-list-item selectable key="L5-2" label="Label for L5-2">
68
- <d2l-list-item-content>
69
- <div>Topic 2 (L5)</div>
70
- <div slot="supporting-info">Supporting Info</div>
71
- </d2l-list-item-content>
72
- <d2l-list slot="nested" separators="all">
73
- <d2l-list-item selectable key="L6-1" label="Label for L6-1">
74
- <d2l-list-item-content>
75
- <div>Sub-Topic 1 (L6)</div>
76
- <div slot="supporting-info">Supporting Info</div>
77
- </d2l-list-item-content>
78
- <d2l-list slot="nested" separators="all">
79
- <d2l-list-item selectable key="L7-1" label="Label for L7-1">
80
- <d2l-list-item-content>
81
- <div>Sub-Topic 1 (L7)</div>
82
- <div slot="supporting-info">Supporting Info</div>
83
- </d2l-list-item-content>
84
- <d2l-list slot="nested" separators="all">
85
- <d2l-list-item selectable selected key="L8-1" label="Label for L8-1">
86
- <d2l-list-item-content>
87
- <div>Sub-Topic 1 (L8)</div>
88
- <div slot="supporting-info">Supporting Info</div>
89
- </d2l-list-item-content>
90
- </d2l-list-item>
91
- <d2l-list-item selectable key="L8-2" label="Label for L8-2">
92
- <d2l-list-item-content>
93
- <div>Sub-Topic 2 (L8)</div>
94
- <div slot="supporting-info">Supporting Info</div>
95
- </d2l-list-item-content>
96
- </d2l-list-item>
97
- </d2l-list>
98
- </d2l-list-item>
99
- <d2l-list-item selectable key="L7-2" label="Label for L7-2">
100
- <d2l-list-item-content>
101
- <div>Sub-Topic 2 (L7)</div>
102
- <div slot="supporting-info">Supporting Info</div>
103
- </d2l-list-item-content>
104
- </d2l-list-item>
105
- </d2l-list>
106
- </d2l-list-item>
107
- <d2l-list-item selectable key="L6-2" label="Label for L6-2">
108
- <d2l-list-item-content>
109
- <div>Sub-Topic 2 (L6)</div>
110
- <div slot="supporting-info">Supporting Info</div>
111
- </d2l-list-item-content>
112
- </d2l-list-item>
113
- </d2l-list>
114
- </d2l-list-item>
115
- </d2l-list>
116
60
  </d2l-list-item>
117
61
  <d2l-list-item selectable key="L4-2" label="Label for L4-2">
118
62
  <d2l-list-item-content>
@@ -175,7 +119,7 @@
175
119
 
176
120
  <d2l-demo-snippet>
177
121
  <template>
178
- <d2l-list>
122
+ <d2l-list grid>
179
123
  <d2l-list-header slot="header">
180
124
  <d2l-selection-action icon="tier1:bookmark-hollow" text="Bookmark" requires-selection></d2l-selection-action>
181
125
  <d2l-selection-action icon="tier1:gear" text="Settings"></d2l-selection-action>
@@ -207,6 +207,7 @@ class ListItemGenericLayout extends RtlMixin(LitElement) {
207
207
  _focusNextCell(num, forward = true) {
208
208
  let cell = null;
209
209
  let focusable = null;
210
+
210
211
  do {
211
212
  cell = this.shadowRoot.querySelector(`[data-cell-num="${num}"]`);
212
213
  if (cell) {
@@ -215,26 +216,31 @@ class ListItemGenericLayout extends RtlMixin(LitElement) {
215
216
  if (focusable) focusable.focus();
216
217
  forward ? ++num : --num;
217
218
  } while (cell && !focusable);
219
+
220
+ if (!cell) {
221
+ // wrap to first/last item
222
+ if (forward) this._focusNextCell(1);
223
+ else this._focusLastItem();
224
+ }
225
+
218
226
  return focusable;
219
227
  }
220
228
 
221
229
  _focusNextRow(previous = false, num = 1) {
222
- let listItem = previous ?
223
- getPreviousAncestorSibling(this, (node) => node.role === 'rowgroup') :
224
- getNextAncestorSibling(this, (node) => node.role === 'rowgroup');
225
- if (!listItem || !listItem.shadowRoot) return;
226
- while (num > 1) {
227
- const nextItem = previous ? listItem.previousElementSibling : listItem.nextElementSibling;
228
- if (!nextItem) {
229
- break; //we ran out of items
230
- }
231
- listItem = nextItem;
232
- --num;
230
+
231
+ let listItem = findComposedAncestor(this, node => node.role === 'rowgroup');
232
+
233
+ while (num > 0) {
234
+ const tempListItem = (previous ? this._getPreviousFlattenedListItem(listItem) : this._getNextFlattenedListItem(listItem));
235
+ if (tempListItem) listItem = tempListItem;
236
+ else break;
237
+ num--;
233
238
  }
234
- const row = listItem.shadowRoot.querySelector('[role="gridrow"]');
235
- if (!row) return;
236
239
 
237
- row._focusCellItem(this._cellNum, this._cellFocusedItem);
240
+ if (!listItem) return;
241
+ const listItemRow = listItem.shadowRoot.querySelector('[role="gridrow"]');
242
+ listItemRow._focusCellItem(this._cellNum, this._cellFocusedItem);
243
+
238
244
  }
239
245
 
240
246
  _focusNextWithinCell(node, num = 1) {
@@ -280,6 +286,38 @@ class ListItemGenericLayout extends RtlMixin(LitElement) {
280
286
  return position;
281
287
  }
282
288
 
289
+ _getNextFlattenedListItem(listItem) {
290
+
291
+ // check for nested list first; this check needs to account for standard list-items as well as custom
292
+ const nestedList = listItem.querySelector('[slot="nested"]') || listItem.shadowRoot.querySelector('d2l-list');
293
+ if (nestedList) {
294
+ const nestedListItem = [...nestedList.children].find(node => node.role === 'rowgroup');
295
+ if (nestedListItem) return nestedListItem;
296
+ }
297
+
298
+ const getNextListItem = listItem => {
299
+
300
+ // check for sibling list-item
301
+ let nextElement = listItem.nextElementSibling;
302
+ while (nextElement) {
303
+ if (nextElement.role === 'rowgroup') return nextElement;
304
+ nextElement = nextElement.nextElementSibling;
305
+ }
306
+
307
+ // no sibling list-item was found so check for sibling of parent list-item if nested, recursively if necessary
308
+ const list = findComposedAncestor(listItem, node => node.tagName === 'D2L-LIST');
309
+ if (list.slot !== 'nested' && !(list.parentNode.tagName === 'SLOT' && list.parentNode.name === 'nested')) return;
310
+
311
+ const parentListItem = findComposedAncestor(list, node => node.role === 'rowgroup');
312
+ return getNextListItem(parentListItem);
313
+
314
+ };
315
+
316
+ // check for sibling list-item or ancestors sibling list-items
317
+ return getNextListItem(listItem);
318
+
319
+ }
320
+
283
321
  _getNextSiblingInCell(node) {
284
322
  const cell = findComposedAncestor(node, (parent) => parent.classList && parent.classList.contains('d2l-cell'));
285
323
  if (!cell || cell.name === node.slot) return null;
@@ -289,6 +327,39 @@ class ListItemGenericLayout extends RtlMixin(LitElement) {
289
327
  return isComposedAncestor(cell, sibling) ? sibling : null;
290
328
  }
291
329
 
330
+ _getPreviousFlattenedListItem(listItem) {
331
+
332
+ let previousElement = listItem.previousElementSibling;
333
+
334
+ // try to get the previous list-item in the current list sub-tree including nested
335
+ while (previousElement) {
336
+ if (previousElement.role === 'rowgroup') {
337
+
338
+ // this check needs to account for standard list-items as well as custom
339
+ const nestedList = previousElement.querySelector('[slot="nested"]') || previousElement.shadowRoot.querySelector('d2l-list');
340
+ if (nestedList) {
341
+ const nestedListItems = [...nestedList.children].filter(node => node.role === 'rowgroup');
342
+ if (nestedListItems && nestedListItems.length > 0) {
343
+ return nestedListItems[nestedListItems.length - 1];
344
+ }
345
+ }
346
+ return previousElement;
347
+
348
+ }
349
+ previousElement = previousElement.previousElementSibling;
350
+ }
351
+
352
+ // no previous list-item was found in the current list sub-tree so get the parent list item if currently in nested
353
+ const list = findComposedAncestor(listItem, node => node.tagName === 'D2L-LIST');
354
+
355
+ // this check needs to account for standard list-items as well as custom
356
+ if (list.slot === 'nested' || (list.parentNode.tagName === 'SLOT' && list.parentNode.name === 'nested')) {
357
+ const parentListItem = findComposedAncestor(list, node => node.role === 'rowgroup');
358
+ return parentListItem;
359
+ }
360
+
361
+ }
362
+
292
363
  _getPrevSiblingInCell(node) {
293
364
  const cell = findComposedAncestor(node, (parent) => parent.classList && parent.classList.contains('d2l-cell'));
294
365
  if (!cell || cell.name === node.slot) return null;
@@ -1,12 +1,16 @@
1
1
  import { css, html, LitElement } from 'lit-element/lit-element.js';
2
+ import { getNextFocusable, getPreviousFocusable } from '../../helpers/focus.js';
2
3
  import { SelectionInfo, SelectionMixin } from '../selection/selection-mixin.js';
3
4
 
5
+ const keyCodes = {
6
+ TAB: 9
7
+ };
8
+
4
9
  export const listSelectionStates = SelectionInfo.states;
5
10
 
6
11
  /**
7
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.
8
13
  * @slot - List content (e.g., `listitem`s)
9
- * @fires d2l-list-selection-change - Dispatched when the selection state changes
10
14
  */
11
15
  class List extends SelectionMixin(LitElement) {
12
16
 
@@ -54,6 +58,7 @@ class List extends SelectionMixin(LitElement) {
54
58
  // batch the changes from select-all and nested lists
55
59
  if (this._listItemChanges.length === 0) {
56
60
  setTimeout(() => {
61
+ /** 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 */
57
62
  this.dispatchEvent(new CustomEvent('d2l-list-selection-changes', {
58
63
  detail: this._listItemChanges
59
64
  }));
@@ -63,6 +68,7 @@ class List extends SelectionMixin(LitElement) {
63
68
  this._listItemChanges.push(e.detail);
64
69
 
65
70
  setTimeout(() => {
71
+ /** Dispatched when the selection state changes */
66
72
  this.dispatchEvent(new CustomEvent('d2l-list-selection-change', {
67
73
  bubbles: true,
68
74
  composed: true,
@@ -78,7 +84,7 @@ class List extends SelectionMixin(LitElement) {
78
84
  return html`
79
85
  <div role="${role}" class="d2l-list-container">
80
86
  <slot name="header"></slot>
81
- <slot></slot>
87
+ <slot @keydown="${this._handleKeyDown}"></slot>
82
88
  </div>
83
89
  `;
84
90
  }
@@ -91,6 +97,17 @@ class List extends SelectionMixin(LitElement) {
91
97
  return this._getItems().indexOf(item);
92
98
  }
93
99
 
100
+ getSelectedListItems(includeNested) {
101
+ let selectedItems = [];
102
+ this._getItems().forEach(item => {
103
+ if (item.selected) selectedItems.push(item);
104
+ if (includeNested && item._selectionProvider) {
105
+ selectedItems = [...selectedItems, ...item._selectionProvider.getSelectedListItems(includeNested)];
106
+ }
107
+ });
108
+ return selectedItems;
109
+ }
110
+
94
111
  getSelectionInfo(includeNested) {
95
112
  const selectionInfo = super.getSelectionInfo();
96
113
  if (!includeNested) return selectionInfo;
@@ -114,6 +131,14 @@ class List extends SelectionMixin(LitElement) {
114
131
  });
115
132
  }
116
133
 
134
+ _handleKeyDown(e) {
135
+ if (!this.grid || this.slot === 'nested' || e.keyCode !== keyCodes.TAB) return;
136
+ e.preventDefault();
137
+ const focusable = (e.shiftKey ? getPreviousFocusable(this.shadowRoot.querySelector('slot:not([name])'))
138
+ : getNextFocusable(this, false, true, true));
139
+ if (focusable) focusable.focus();
140
+ }
141
+
117
142
  }
118
143
 
119
144
  customElements.define('d2l-list', List);
@@ -89,10 +89,12 @@ class Input extends SkeletonMixin(LabelledMixin(LitElement)) {
89
89
  'd2l-input-radio': true,
90
90
  'd2l-selection-input-radio': true,
91
91
  'd2l-skeletize': true,
92
- 'd2l-hovering': this.hovering
92
+ 'd2l-hovering': this.hovering,
93
+ 'd2l-disabled': this.disabled
93
94
  };
94
95
  return html`
95
96
  <div
97
+ aria-disabled="${ifDefined(this.disabled)}"
96
98
  aria-label="${this.label}"
97
99
  aria-checked="${this.selected ? 'true' : 'false'}"
98
100
  class="${classMap(radioClasses)}"
@@ -100,7 +102,7 @@ class Input extends SkeletonMixin(LabelledMixin(LitElement)) {
100
102
  @keydown="${this._handleRadioKeyDown}"
101
103
  @keyup="${this._handleRadioKeyUp}"
102
104
  role="radio"
103
- tabindex="0"></div>
105
+ tabindex="${ifDefined(this.disabled ? undefined : 0)}"></div>
104
106
  `;
105
107
  } else {
106
108
  return html`
@@ -60,6 +60,7 @@ export const SelectionMixin = superclass => class extends RtlMixin(superclass) {
60
60
  this.addEventListener('d2l-selection-observer-subscribe', this._handleSelectionObserverSubscribe);
61
61
  this.addEventListener('d2l-selection-input-subscribe', this._handleSelectionInputSubscribe);
62
62
  requestAnimationFrame(() => {
63
+ /** @ignore */
63
64
  this.dispatchEvent(new CustomEvent('d2l-selection-provider-connected', { bubbles: true, composed: true }));
64
65
  });
65
66
 
@@ -234,6 +234,7 @@ export const SwitchMixin = superclass => class extends RtlMixin(FocusVisiblePoly
234
234
  _toggleState() {
235
235
  if (this.disabled) return;
236
236
  this.on = !this.on;
237
+ /** Dispatched when the `on` property is updated */
237
238
  this.dispatchEvent(new CustomEvent('change', { bubbles: true }));
238
239
  }
239
240
  };