@brightspace-ui/core 1.226.0 → 1.229.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -311,7 +311,8 @@ The `d2l-list-header` component can be placed in the `d2l-list`'s `header` slot
311
311
 
312
312
  | Property | Type | Description |
313
313
  |---|---|---|
314
- | `slim` | Boolean | Whether to render a header with reduced whitespace |
314
+ | `padding-type` | String | Header whitespace (`normal` (default), `slim`) |
315
+ | `select-all-pages-allowed` | Boolean | Whether all pages can be selected |
315
316
  <!-- docs: end hidden content -->
316
317
 
317
318
  ## List Item [d2l-list-item]
@@ -354,16 +355,17 @@ The `d2l-list-item` provides the appropriate `listitem` semantics for children w
354
355
  | `disabled` | Boolean | Disables the input |
355
356
  | `draggable` | Boolean | Whether the item is draggable |
356
357
  | `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. |
358
+ | `drag-target-handle-only` | Boolean | Make the drag target the drag handle only. |
357
359
  | `drop-nested` | Boolean | Whether nested items can be dropped on this item |
358
360
  | `drop-text` | String | Text to drag and drop |
359
361
  | `href` | String | Address of item link if navigable |
360
362
  | `key` | String | Value to identify item if selectable or draggable |
361
363
  | `label` | String | Explicitly defined label for the element |
362
364
  | `labelled-by` | String | The id of element that provides the label for this element |
365
+ | `padding-type` | String | List item whitespace (`normal` (default), `slim`, `none`)|
363
366
  | `selectable` | Boolean | Indicates an input should be rendered for selecting the item |
364
367
  | `selected` | Boolean | Whether the item is selected |
365
368
  | `skeleton` | Boolean | Renders the input as a skeleton loader |
366
- | `slim` | Boolean | Whether to render the list-item with reduced whitespace|
367
369
 
368
370
  ### Events
369
371
 
@@ -64,11 +64,10 @@
64
64
 
65
65
  <d2l-demo-snippet>
66
66
  <template>
67
- <d2l-list>
68
- <d2l-list-header slot="header">
69
- <d2l-selection-action icon="tier1:tag-hollow" text="Tag" requires-selection></d2l-selection-action>
67
+ <d2l-list id="allFeatures" item-count="50">
68
+ <d2l-list-header slot="header" select-all-pages-allowed>
69
+ <d2l-selection-action icon="tier1:plus-default" text="Add"></d2l-selection-action>
70
70
  <d2l-selection-action icon="tier1:share" text="Share" requires-selection></d2l-selection-action>
71
- <d2l-selection-action icon="tier1:bookmark-hollow" text="Bookmark" requires-selection></d2l-selection-action>
72
71
  <d2l-selection-action icon="tier1:delete" text="Delete" requires-selection></d2l-selection-action>
73
72
  <d2l-selection-action icon="tier1:gear" text="Settings"></d2l-selection-action>
74
73
  </d2l-list-header>
@@ -130,6 +129,23 @@
130
129
  </div>
131
130
  </d2l-list-item>
132
131
  </d2l-list>
132
+ <script>
133
+ let newItemCount = 0;
134
+ document.querySelector('d2l-selection-action[text="Add"]').addEventListener('d2l-selection-action-click', () => {
135
+ const item = document.createElement('d2l-list-item');
136
+ item.selectable = true;
137
+ item.key = `${++newItemCount}`;
138
+ item.label = 'New Item';
139
+ item.innerHTML = `
140
+ <img slot="illustration" src="https://s.brightspace.com/course-images/images/38e839b1-37fa-470c-8830-b189ce4ae134/tile-high-density-max-size.jpg"></img>
141
+ <d2l-list-item-content>
142
+ <div>New Item ${newItemCount}</div>
143
+ <div slot="supporting-info">Supporting Info</div>
144
+ </d2l-list-item-content>
145
+ `;
146
+ document.querySelector('#allFeatures').appendChild(item);
147
+ });
148
+ </script>
133
149
  </template>
134
150
  </d2l-demo-snippet>
135
151
 
@@ -1,5 +1,6 @@
1
1
  import '../overflow-group/overflow-group.js';
2
2
  import '../selection/selection-select-all.js';
3
+ import '../selection/selection-select-all-pages.js';
3
4
  import '../selection/selection-summary.js';
4
5
  import { css, html, LitElement } from 'lit-element/lit-element.js';
5
6
  import { LocalizeCoreElement } from '../../lang/localize-core-element.js';
@@ -14,10 +15,22 @@ class ListHeader extends RtlMixin(LocalizeCoreElement(LitElement)) {
14
15
  static get properties() {
15
16
  return {
16
17
  /**
18
+ * @ignore
17
19
  * Whether to render a header with reduced whitespace
20
+ * TODO: Remove
18
21
  * @type {boolean}
19
22
  */
20
- slim: { reflect: true, type: Boolean }
23
+ slim: { reflect: true, type: Boolean },
24
+ /**
25
+ * How much padding to render list items with
26
+ * @type {'normal'|'slim'}
27
+ */
28
+ paddingType: { type: String, attribute: 'padding-type' },
29
+ /**
30
+ * Whether all pages can be selected
31
+ * @type {boolean}
32
+ */
33
+ selectAllPagesAllowed: { type: Boolean, attribute: 'select-all-pages-allowed' },
21
34
  };
22
35
  }
23
36
 
@@ -36,7 +49,10 @@ class ListHeader extends RtlMixin(LocalizeCoreElement(LitElement)) {
36
49
  margin-top: 6px;
37
50
  min-height: 58px;
38
51
  }
39
- :host([slim]) .d2l-list-header-container {
52
+ :host([slim]) .d2l-list-header-container { /* TODO: Remove */
53
+ min-height: 36px;
54
+ }
55
+ :host([padding-type="slim"]) .d2l-list-header-container {
40
56
  min-height: 36px;
41
57
  }
42
58
  d2l-selection-select-all {
@@ -50,6 +66,14 @@ class ListHeader extends RtlMixin(LocalizeCoreElement(LitElement)) {
50
66
  margin-left: 0;
51
67
  margin-right: 0.9rem;
52
68
  }
69
+ d2l-selection-select-all-pages {
70
+ flex: none;
71
+ margin-left: 0.45rem;
72
+ }
73
+ :host([dir="rtl"]) d2l-selection-select-all-pages {
74
+ margin-left: 0;
75
+ margin-right: 0.45rem;
76
+ }
53
77
  .d2l-list-header-actions {
54
78
  --d2l-overflow-group-justify-content: flex-end;
55
79
  flex: auto;
@@ -64,6 +88,8 @@ class ListHeader extends RtlMixin(LocalizeCoreElement(LitElement)) {
64
88
  constructor() {
65
89
  super();
66
90
  this.slim = false;
91
+ this.paddingType = 'normal';
92
+ this.selectAllPagesAllowed = false;
67
93
  }
68
94
 
69
95
  render() {
@@ -75,6 +101,7 @@ class ListHeader extends RtlMixin(LocalizeCoreElement(LitElement)) {
75
101
  class="d2l-list-header-summary"
76
102
  no-selection-text="${this.localize('components.selection.select-all')}">
77
103
  </d2l-selection-summary>
104
+ ${this.selectAllPagesAllowed ? html`<d2l-selection-select-all-pages></d2l-selection-select-all-pages>` : null}
78
105
  <div class="d2l-list-header-actions">
79
106
  <d2l-overflow-group opener-type="icon"><slot></slot></d2l-overflow-group>
80
107
  </div>
@@ -54,7 +54,19 @@ export const ListItemMixin = superclass => class extends LocalizeCoreElement(Lis
54
54
  */
55
55
  breakpoints: { type: Array },
56
56
  /**
57
+ * Whether to allow the drag target to be the handle only rather than the entire cell
58
+ * @type {boolean}
59
+ */
60
+ dragTargetHandleOnly: { type: Boolean, attribute: 'drag-target-handle-only' },
61
+ /**
62
+ * How much padding to render list items with
63
+ * @type {'normal'|'slim'|'none'}
64
+ */
65
+ paddingType: { type: String, attribute: 'padding-type' },
66
+ /**
67
+ * @ignore
57
68
  * Whether to render the list-item with reduced whitespace.
69
+ * TODO: Remove in favor of padding-type="slim"
58
70
  * @type {boolean}
59
71
  */
60
72
  slim: { type: Boolean },
@@ -106,6 +118,10 @@ export const ListItemMixin = superclass => class extends LocalizeCoreElement(Lis
106
118
  border-bottom: 1px solid var(--d2l-color-mica);
107
119
  border-top: 1px solid var(--d2l-color-mica);
108
120
  }
121
+ :host([padding-type="none"]) d2l-list-item-generic-layout {
122
+ border-bottom: 0;
123
+ border-top: 0;
124
+ }
109
125
  d2l-list-item-generic-layout[data-separators="none"] {
110
126
  border-bottom: 1px solid transparent;
111
127
  border-top: 1px solid transparent;
@@ -143,10 +159,18 @@ export const ListItemMixin = superclass => class extends LocalizeCoreElement(Lis
143
159
  justify-content: stretch;
144
160
  padding: 0.55rem 0;
145
161
  }
146
- :host([slim]) [slot="content"] {
162
+ :host([slim]) [slot="content"] { /* TODO, remove */
147
163
  padding-bottom: 0.35rem;
148
164
  padding-top: 0.4rem;
149
165
  }
166
+ :host([padding-type="slim"]) [slot="content"] {
167
+ padding-bottom: 0.35rem;
168
+ padding-top: 0.4rem;
169
+ }
170
+ :host([padding-type="none"]) [slot="content"] {
171
+ padding-bottom: 0;
172
+ padding-top: 0;
173
+ }
150
174
  [slot="content"] ::slotted([slot="illustration"]),
151
175
  [slot="content"] .d2l-list-item-illustration * {
152
176
  border-radius: 6px;
@@ -219,7 +243,11 @@ export const ListItemMixin = superclass => class extends LocalizeCoreElement(Lis
219
243
  .d2l-list-item-content-extend-separators d2l-selection-input {
220
244
  margin-left: 0.9rem;
221
245
  }
222
- :host([slim]) d2l-selection-input {
246
+ :host([slim]) d2l-selection-input { /* TODO, remove */
247
+ margin-bottom: 0.55rem;
248
+ margin-top: 0.55rem;
249
+ }
250
+ :host([padding-type="slim"]) d2l-selection-input {
223
251
  margin-bottom: 0.55rem;
224
252
  margin-top: 0.55rem;
225
253
  }
@@ -276,6 +304,7 @@ export const ListItemMixin = superclass => class extends LocalizeCoreElement(Lis
276
304
  super();
277
305
  this.breakpoints = defaultBreakpoints;
278
306
  this.slim = false;
307
+ this.paddingType = 'normal';
279
308
  this._breakpoint = 0;
280
309
  this._contentId = getUniqueId();
281
310
  this._displayKeyboardTooltip = false;
@@ -449,7 +478,7 @@ export const ListItemMixin = superclass => class extends LocalizeCoreElement(Lis
449
478
  ?grid-active="${this.role === 'rowgroup'}">
450
479
  ${this._renderDropTarget()}
451
480
  ${this._renderDragHandle(this._renderOutsideControl)}
452
- ${this._renderDragTarget(this._renderOutsideControlAction)}
481
+ ${this._renderDragTarget(this.dragTargetHandleOnly ? this._renderOutsideControlHandleOnly : this._renderOutsideControlAction)}
453
482
  ${this.selectable ? html`
454
483
  <div slot="control">${this._renderCheckbox()}</div>
455
484
  <div slot="control-action"
@@ -497,6 +526,10 @@ export const ListItemMixin = superclass => class extends LocalizeCoreElement(Lis
497
526
  return html`<div slot="outside-control-action" @mouseenter="${this._onMouseEnter}" @mouseleave="${this._onMouseLeave}">${dragTarget}</div>`;
498
527
  }
499
528
 
529
+ _renderOutsideControlHandleOnly(dragHandle) {
530
+ return html`<div slot="outside-control" @mouseenter="${this._onMouseEnter}" @mouseleave="${this._onMouseLeave}">${dragHandle}</div>`;
531
+ }
532
+
500
533
  _renderTooltipContent() {
501
534
  return html`
502
535
  <div>${this.localize('components.list-item-tooltip.title')}</div>
@@ -97,6 +97,7 @@ The `d2l-list` already extends `SelectionMixin` and should always be used for li
97
97
 
98
98
  | Property | Type | Description |
99
99
  |---|---|---|
100
+ | `item-count` | Number | Total number of items. Required when selecting all pages is allowed. |
100
101
  | `selection-single` | Boolean | Whether to render with single selection behaviour. If `selection-single` is specified, the nested `d2l-selection-input` elements will render radios instead of checkboxes, and the selection component will maintain a single selected item. |
101
102
  <!-- docs: end hidden content -->
102
103
 
@@ -74,6 +74,7 @@ class Input extends SkeletonMixin(LabelledMixin(LitElement)) {
74
74
  });
75
75
  this.dispatchEvent(evt);
76
76
  this._provider = evt.detail.provider;
77
+ if (this._provider && this._provider._selectAllPages) this.selected = true;
77
78
  });
78
79
  }
79
80
 
@@ -28,7 +28,8 @@ export class SelectionInfo {
28
28
  return {
29
29
  none: 'none',
30
30
  some: 'some',
31
- all: 'all'
31
+ all: 'all',
32
+ allPages: 'all-pages'
32
33
  };
33
34
  }
34
35
 
@@ -38,6 +39,11 @@ export const SelectionMixin = superclass => class extends RtlMixin(superclass) {
38
39
 
39
40
  static get properties() {
40
41
  return {
42
+ /**
43
+ * Total number of items. Required when selecting all pages is allowed.
44
+ * @type {number}
45
+ */
46
+ itemCount: { type: Number, attribute: 'item-count' },
41
47
  /**
42
48
  * Whether to render with single selection behaviour. If `selection-single` is specified, the nested `d2l-selection-input` elements will render radios instead of checkboxes, and the selection component will maintain a single selected item.
43
49
  * @type {boolean}
@@ -48,7 +54,9 @@ export const SelectionMixin = superclass => class extends RtlMixin(superclass) {
48
54
 
49
55
  constructor() {
50
56
  super();
57
+ this.itemCount = 0;
51
58
  this.selectionSingle = false;
59
+ this._selectAllPages = false;
52
60
  this._selectionObservers = new Map();
53
61
  this._selectionSelectables = new Map();
54
62
  }
@@ -80,22 +88,28 @@ export const SelectionMixin = superclass => class extends RtlMixin(superclass) {
80
88
  let state = SelectionInfo.states.none;
81
89
  const keys = [];
82
90
 
83
- this._selectionSelectables.forEach(selectable => {
84
- if (selectable.selected) keys.push(selectable.key);
85
- if (selectable._indeterminate) state = SelectionInfo.states.some;
86
- });
91
+ if (this._selectAllPages) {
92
+ state = SelectionInfo.states.allPages;
93
+ } else {
94
+ this._selectionSelectables.forEach(selectable => {
95
+ if (selectable.selected) keys.push(selectable.key);
96
+ if (selectable._indeterminate) state = SelectionInfo.states.some;
97
+ });
87
98
 
88
- if (keys.length > 0) {
89
- if (keys.length === this._selectionSelectables.size) state = SelectionInfo.states.all;
90
- else state = SelectionInfo.states.some;
99
+ if (keys.length > 0) {
100
+ if (keys.length === this._selectionSelectables.size) state = SelectionInfo.states.all;
101
+ else state = SelectionInfo.states.some;
102
+ }
91
103
  }
92
104
 
93
105
  return new SelectionInfo(keys, state);
94
106
  }
95
107
 
96
- setSelectionForAll(selected) {
108
+ setSelectionForAll(selected, selectAllPages) {
97
109
  if (this.selectionSingle && selected) return;
98
110
 
111
+ this._selectAllPages = (selected && selectAllPages);
112
+
99
113
  this._selectionSelectables.forEach(selectable => {
100
114
  if (!!selectable.selected !== selected) {
101
115
  selectable.selected = selected;
@@ -154,6 +168,7 @@ export const SelectionMixin = superclass => class extends RtlMixin(superclass) {
154
168
  }
155
169
 
156
170
  _handleSelectionChange(e) {
171
+ if (!e.detail.selected) this._selectAllPages = false;
157
172
  if (this.selectionSingle && e.detail.selected) {
158
173
  const target = e.composedPath().find(elem => elem.tagName === 'D2L-SELECTION-INPUT');
159
174
  this._selectionSelectables.forEach(selectable => {
@@ -0,0 +1,48 @@
1
+ import '../button/button-subtle.js';
2
+ import { css, html, LitElement } from 'lit-element/lit-element.js';
3
+ import { LocalizeCoreElement } from '../../lang/localize-core-element.js';
4
+ import { SelectionInfo } from './selection-mixin.js';
5
+ import { SelectionObserverMixin } from './selection-observer-mixin.js';
6
+
7
+ /**
8
+ * A subtle button that selects all items for all pages.
9
+ * @fires d2l-selection-observer-subscribe - Internal event
10
+ */
11
+ class SelectAllPages extends LocalizeCoreElement(SelectionObserverMixin(LitElement)) {
12
+
13
+ static get styles() {
14
+ return css`
15
+ :host {
16
+ display: inline-block;
17
+ }
18
+ :host([hidden]) {
19
+ display: none;
20
+ }
21
+ `;
22
+ }
23
+
24
+ render() {
25
+ if (!this._provider) return;
26
+ if (!this._provider.itemCount) return;
27
+ if (this._provider.selectionSingle) return;
28
+ if (this.selectionInfo.state !== SelectionInfo.states.all) return;
29
+
30
+ return html`
31
+ <d2l-button-subtle
32
+ @click="${this._handleClick}"
33
+ text="${this.localize('components.selection.select-all-items', 'count', this._provider.itemCount)}">
34
+ </d2l-button-subtle>`;
35
+ }
36
+
37
+ focus() {
38
+ const elem = this.shadowRoot && this.shadowRoot.querySelector('d2l-button-subtle');
39
+ if (elem) elem.focus();
40
+ }
41
+
42
+ _handleClick() {
43
+ if (this._provider) this._provider.setSelectionForAll(true, true);
44
+ }
45
+
46
+ }
47
+
48
+ customElements.define('d2l-selection-select-all-pages', SelectAllPages);
@@ -48,7 +48,7 @@ class SelectAll extends LocalizeCoreElement(SelectionObserverMixin(LitElement))
48
48
  <d2l-input-checkbox
49
49
  aria-label="${this.localize('components.selection.select-all')}"
50
50
  @change="${this._handleCheckboxChange}"
51
- ?checked="${this.selectionInfo.state === SelectionInfo.states.all}"
51
+ ?checked="${this.selectionInfo.state === SelectionInfo.states.all || this.selectionInfo.state === SelectionInfo.states.allPages}"
52
52
  ?disabled="${this.disabled}"
53
53
  description="${ifDefined(this.selectionInfo.state !== SelectionInfo.states.none ? summary : undefined)}"
54
54
  ?indeterminate="${this.selectionInfo.state === SelectionInfo.states.some}">
@@ -62,7 +62,7 @@ class SelectAll extends LocalizeCoreElement(SelectionObserverMixin(LitElement))
62
62
  }
63
63
 
64
64
  _handleCheckboxChange(e) {
65
- if (this._provider) this._provider.setSelectionForAll(e.target.checked);
65
+ if (this._provider) this._provider.setSelectionForAll(e.target.checked, false);
66
66
  }
67
67
 
68
68
  }
@@ -37,8 +37,12 @@ class Summary extends LocalizeCoreElement(SelectionObserverMixin(LitElement)) {
37
37
  render() {
38
38
  if (this._provider && this._provider.selectionSingle) return;
39
39
 
40
+ const count = (this.selectionInfo.state === SelectionInfo.states.allPages ?
41
+ this._provider.itemCount : this.selectionInfo.keys.length);
42
+
40
43
  const summary = (this.selectionInfo.state === SelectionInfo.states.none && this.noSelectionText ?
41
- this.noSelectionText : this.localize('components.selection.selected', 'count', this.selectionInfo.keys.length));
44
+ this.noSelectionText : this.localize('components.selection.selected', 'count', count));
45
+
42
46
  return html`
43
47
  <p class="d2l-body-compact">${summary}</p>
44
48
  `;