@brightspace-ui/core 2.104.2 → 2.106.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.
- package/components/button/button-move.js +63 -41
- package/components/button/demo/button-move.html +1 -9
- package/components/list/demo/demo-list-nested.js +1 -2
- package/components/list/demo/demo-list.js +0 -1
- package/components/list/list.js +14 -35
- package/components/paging/README.md +3 -11
- package/components/paging/demo/pager-load-more.html +2 -2
- package/components/paging/pageable-mixin.js +42 -15
- package/components/paging/pageable-subscriber-mixin.js +33 -0
- package/components/paging/pager-load-more.js +9 -18
- package/components/selection/selection-mixin.js +2 -7
- package/controllers/subscriber/subscriberControllers.js +7 -1
- package/custom-elements.json +126 -108
- package/mixins/collection/README.md +36 -0
- package/mixins/collection/collection-mixin.js +18 -0
- package/package.json +1 -1
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import '../colors/colors.js';
|
|
2
2
|
import '../icons/icon.js';
|
|
3
3
|
import '../tooltip/tooltip.js';
|
|
4
|
-
import { css, html, LitElement } from 'lit';
|
|
4
|
+
import { css, html, LitElement, unsafeCSS } from 'lit';
|
|
5
5
|
import { buttonStyles } from './button-styles.js';
|
|
6
6
|
import { FocusMixin } from '../../mixins/focus/focus-mixin.js';
|
|
7
|
+
import { getFocusPseudoClass } from '../../helpers/focus.js';
|
|
7
8
|
import { getUniqueId } from '../../helpers/uniqueId.js';
|
|
8
9
|
import { ifDefined } from 'lit/directives/if-defined.js';
|
|
9
10
|
import { RtlMixin } from '../../mixins/rtl/rtl-mixin.js';
|
|
11
|
+
import { ThemeMixin } from '../../mixins/theme/theme-mixin.js';
|
|
10
12
|
|
|
11
13
|
const keyCodes = Object.freeze({
|
|
12
14
|
DOWN: 40,
|
|
@@ -31,7 +33,7 @@ export const moveActions = Object.freeze({
|
|
|
31
33
|
/**
|
|
32
34
|
* A button component that provides a move action via a single button.
|
|
33
35
|
*/
|
|
34
|
-
class ButtonMove extends FocusMixin(RtlMixin(LitElement)) {
|
|
36
|
+
class ButtonMove extends ThemeMixin(FocusMixin(RtlMixin(LitElement))) {
|
|
35
37
|
|
|
36
38
|
static get properties() {
|
|
37
39
|
return {
|
|
@@ -45,15 +47,35 @@ class ButtonMove extends FocusMixin(RtlMixin(LitElement)) {
|
|
|
45
47
|
*/
|
|
46
48
|
description: { type: String },
|
|
47
49
|
/**
|
|
48
|
-
* Disables the
|
|
50
|
+
* Disables the down interaction
|
|
49
51
|
* @type {boolean}
|
|
50
52
|
*/
|
|
51
|
-
|
|
53
|
+
disabledDown: { type: Boolean, attribute: 'disabled-down', reflect: true },
|
|
52
54
|
/**
|
|
53
|
-
*
|
|
54
|
-
* @type {
|
|
55
|
+
* Disables the end interaction
|
|
56
|
+
* @type {boolean}
|
|
57
|
+
*/
|
|
58
|
+
disabledEnd: { type: Boolean, attribute: 'disabled-end', reflect: true },
|
|
59
|
+
/**
|
|
60
|
+
* Disables the home interaction
|
|
61
|
+
* @type {boolean}
|
|
62
|
+
*/
|
|
63
|
+
disabledHome: { type: Boolean, attribute: 'disabled-home', reflect: true },
|
|
64
|
+
/**
|
|
65
|
+
* Disables the left interaction
|
|
66
|
+
* @type {boolean}
|
|
55
67
|
*/
|
|
56
|
-
|
|
68
|
+
disabledLeft: { type: Boolean, attribute: 'disabled-left', reflect: true },
|
|
69
|
+
/**
|
|
70
|
+
* Disables the right interaction
|
|
71
|
+
* @type {boolean}
|
|
72
|
+
*/
|
|
73
|
+
disabledRight: { type: Boolean, attribute: 'disabled-right', reflect: true },
|
|
74
|
+
/**
|
|
75
|
+
* Disables the up interaction
|
|
76
|
+
* @type {boolean}
|
|
77
|
+
*/
|
|
78
|
+
disabledUp: { type: Boolean, attribute: 'disabled-up', reflect: true },
|
|
57
79
|
/**
|
|
58
80
|
* REQUIRED: Accessible text for the button
|
|
59
81
|
* @type {string}
|
|
@@ -67,12 +89,22 @@ class ButtonMove extends FocusMixin(RtlMixin(LitElement)) {
|
|
|
67
89
|
return [ buttonStyles,
|
|
68
90
|
css`
|
|
69
91
|
:host {
|
|
92
|
+
--d2l-button-move-background-color-focus: #ffffff;
|
|
93
|
+
--d2l-button-move-icon-background-color-hover: var(--d2l-color-mica);
|
|
94
|
+
--d2l-button-move-box-shadow-focus: 0 0 0 2px #ffffff, 0 0 0 4px var(--d2l-color-celestine);
|
|
95
|
+
--d2l-icon-fill-color: var(--d2l-color-tungsten);
|
|
70
96
|
display: inline-block;
|
|
71
97
|
line-height: 0;
|
|
72
98
|
}
|
|
73
99
|
:host([hidden]) {
|
|
74
100
|
display: none;
|
|
75
101
|
}
|
|
102
|
+
:host([theme="dark"]) {
|
|
103
|
+
--d2l-button-move-background-color-focus: #000000;
|
|
104
|
+
--d2l-button-move-icon-background-color-hover: rgba(51, 53, 54, 0.9); /* tungsten @70% @90% */
|
|
105
|
+
--d2l-button-move-box-shadow-focus: 0 0 0 2px black, 0 0 0 4px var(--d2l-color-celestine-plus-1);
|
|
106
|
+
--d2l-icon-fill-color: var(--d2l-color-sylvite);
|
|
107
|
+
}
|
|
76
108
|
button {
|
|
77
109
|
background-color: transparent;
|
|
78
110
|
display: flex;
|
|
@@ -90,11 +122,14 @@ class ButtonMove extends FocusMixin(RtlMixin(LitElement)) {
|
|
|
90
122
|
width: 0.9rem;
|
|
91
123
|
}
|
|
92
124
|
button:focus {
|
|
93
|
-
background-color:
|
|
125
|
+
background-color: var(--d2l-button-move-background-color-focus);
|
|
94
126
|
}
|
|
95
127
|
button:hover > d2l-icon,
|
|
96
128
|
button:focus > d2l-icon {
|
|
97
|
-
background-color: var(--d2l-color-
|
|
129
|
+
background-color: var(--d2l-button-move-icon-background-color-hover);
|
|
130
|
+
}
|
|
131
|
+
button:${unsafeCSS(getFocusPseudoClass())} {
|
|
132
|
+
box-shadow: var(--d2l-button-move-box-shadow-focus);
|
|
98
133
|
}
|
|
99
134
|
.up-icon {
|
|
100
135
|
border-top-left-radius: 0.3rem;
|
|
@@ -124,25 +159,27 @@ class ButtonMove extends FocusMixin(RtlMixin(LitElement)) {
|
|
|
124
159
|
right: -0.2rem;
|
|
125
160
|
}
|
|
126
161
|
|
|
127
|
-
|
|
128
162
|
/* Firefox includes a hidden border which messes up button dimensions */
|
|
129
163
|
button::-moz-focus-inner {
|
|
130
164
|
border: 0;
|
|
131
165
|
}
|
|
132
|
-
:host([disabled]) button {
|
|
133
|
-
cursor: default;
|
|
134
|
-
opacity: 0.5;
|
|
135
|
-
}
|
|
136
166
|
button[disabled]:hover > d2l-icon {
|
|
137
167
|
background-color: transparent;
|
|
138
168
|
}
|
|
169
|
+
:host([disabled-up]) .up-icon,
|
|
170
|
+
:host([disabled-down]) .down-icon {
|
|
171
|
+
opacity: 0.5;
|
|
172
|
+
}
|
|
173
|
+
:host([disabled-up]) .up-layer,
|
|
174
|
+
:host([disabled-down]) .down-layer {
|
|
175
|
+
cursor: default;
|
|
176
|
+
}
|
|
139
177
|
`
|
|
140
178
|
];
|
|
141
179
|
}
|
|
142
180
|
|
|
143
181
|
constructor() {
|
|
144
182
|
super();
|
|
145
|
-
this.disabled = false;
|
|
146
183
|
/** @ignore */
|
|
147
184
|
this.autofocus = false;
|
|
148
185
|
/** @internal */
|
|
@@ -155,24 +192,13 @@ class ButtonMove extends FocusMixin(RtlMixin(LitElement)) {
|
|
|
155
192
|
return 'button';
|
|
156
193
|
}
|
|
157
194
|
|
|
158
|
-
connectedCallback() {
|
|
159
|
-
super.connectedCallback();
|
|
160
|
-
this.addEventListener('click', this._handleClick, true);
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
disconnectedCallback() {
|
|
164
|
-
super.disconnectedCallback();
|
|
165
|
-
this.removeEventListener('click', this._handleClick, true);
|
|
166
|
-
}
|
|
167
|
-
|
|
168
195
|
render() {
|
|
169
196
|
return html`
|
|
170
197
|
<button
|
|
171
198
|
aria-describedby="${ifDefined(this.description ? this._describedById : undefined)}"
|
|
172
|
-
aria-disabled="${ifDefined(this.disabled && this.disabledTooltip ? 'true' : undefined)}"
|
|
173
199
|
aria-label="${ifDefined(this.text)}"
|
|
174
200
|
?autofocus="${this.autofocus}"
|
|
175
|
-
?disabled="${this.
|
|
201
|
+
?disabled="${this.disabledUp && this.disabledDown && this.disabledLeft && this.disabledRight && this.disabledHome && this.disabledEnd}"
|
|
176
202
|
id="${this._buttonId}"
|
|
177
203
|
@keydown="${this._handleKeydown}"
|
|
178
204
|
title="${ifDefined(this.text)}"
|
|
@@ -183,7 +209,6 @@ class ButtonMove extends FocusMixin(RtlMixin(LitElement)) {
|
|
|
183
209
|
<div class="down-layer" @click="${this._handleDownClick}"></div>
|
|
184
210
|
</button>
|
|
185
211
|
${this.description ? html`<span id="${this._describedById}" hidden>${this.description}</span>` : null}
|
|
186
|
-
${this.disabled && this.disabledTooltip ? html`<d2l-tooltip for="${this._buttonId}">${this.disabledTooltip}</d2l-tooltip>` : ''}
|
|
187
212
|
`;
|
|
188
213
|
}
|
|
189
214
|
|
|
@@ -195,48 +220,45 @@ class ButtonMove extends FocusMixin(RtlMixin(LitElement)) {
|
|
|
195
220
|
}));
|
|
196
221
|
}
|
|
197
222
|
|
|
198
|
-
_handleClick(e) {
|
|
199
|
-
if (this.disabled) {
|
|
200
|
-
e.stopPropagation();
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
|
|
204
223
|
_handleDownClick() {
|
|
224
|
+
if (this.disabledDown) return;
|
|
205
225
|
this._dispatchAction(moveActions.down);
|
|
206
226
|
}
|
|
207
227
|
|
|
208
228
|
_handleKeydown(e) {
|
|
229
|
+
|
|
209
230
|
let action;
|
|
210
231
|
switch (e.keyCode) {
|
|
211
232
|
case keyCodes.UP:
|
|
212
|
-
action = moveActions.up;
|
|
233
|
+
if (!this.disabledUp) action = moveActions.up;
|
|
213
234
|
break;
|
|
214
235
|
case keyCodes.DOWN:
|
|
215
|
-
action = moveActions.down;
|
|
236
|
+
if (!this.disabledDown) action = moveActions.down;
|
|
216
237
|
break;
|
|
217
238
|
case keyCodes.LEFT:
|
|
218
|
-
action = moveActions.left;
|
|
239
|
+
if (!this.disabledLeft) action = moveActions.left;
|
|
219
240
|
break;
|
|
220
241
|
case keyCodes.RIGHT:
|
|
221
|
-
action = moveActions.right;
|
|
242
|
+
if (!this.disabledRight) action = moveActions.right;
|
|
222
243
|
break;
|
|
223
244
|
case keyCodes.HOME:
|
|
224
|
-
action = (e.ctrlKey ? moveActions.rootHome : moveActions.home);
|
|
245
|
+
if (!this.disabledHome) action = (e.ctrlKey ? moveActions.rootHome : moveActions.home);
|
|
225
246
|
break;
|
|
226
247
|
case keyCodes.END:
|
|
227
|
-
action = (e.ctrlKey ? moveActions.rootEnd : moveActions.end);
|
|
248
|
+
if (!this.disabledEnd) action = (e.ctrlKey ? moveActions.rootEnd : moveActions.end);
|
|
228
249
|
break;
|
|
229
250
|
default:
|
|
230
251
|
return;
|
|
231
252
|
}
|
|
232
253
|
|
|
233
|
-
this._dispatchAction(action);
|
|
254
|
+
if (action) this._dispatchAction(action);
|
|
234
255
|
e.preventDefault();
|
|
235
256
|
e.stopPropagation();
|
|
236
257
|
|
|
237
258
|
}
|
|
238
259
|
|
|
239
260
|
_handleUpClick() {
|
|
261
|
+
if (this.disabledUp) return;
|
|
240
262
|
this._dispatchAction(moveActions.up);
|
|
241
263
|
}
|
|
242
264
|
|
|
@@ -30,15 +30,7 @@
|
|
|
30
30
|
|
|
31
31
|
<d2l-demo-snippet>
|
|
32
32
|
<template>
|
|
33
|
-
<d2l-button-move text="Reorder Item" disabled></d2l-button-move>
|
|
34
|
-
</template>
|
|
35
|
-
</d2l-demo-snippet>
|
|
36
|
-
|
|
37
|
-
<h2>Move Button Disabled with Tooltip</h2>
|
|
38
|
-
|
|
39
|
-
<d2l-demo-snippet>
|
|
40
|
-
<template>
|
|
41
|
-
<d2l-button-move text="Reorder Item" disabled disabled-tooltip="Optional disabled tooltip"></d2l-button-move>
|
|
33
|
+
<d2l-button-move text="Reorder Item" disabled-up disabled-down disabled-left disabled-right disabled-home disabled-end></d2l-button-move>
|
|
42
34
|
</template>
|
|
43
35
|
</d2l-demo-snippet>
|
|
44
36
|
|
|
@@ -169,7 +169,7 @@ class ListDemoNested extends LitElement {
|
|
|
169
169
|
|
|
170
170
|
_renderList(items, nested, includeControls = false, showLoadMore = false) {
|
|
171
171
|
return html`
|
|
172
|
-
<d2l-list ?grid="${!this.disableListGrid}" drag-multiple slot="${ifDefined(nested ? 'nested' : undefined)}">
|
|
172
|
+
<d2l-list ?grid="${!this.disableListGrid}" drag-multiple slot="${ifDefined(nested ? 'nested' : undefined)}" item-count="${this._items.length}">
|
|
173
173
|
${ includeControls ? this._renderListControls() : nothing }
|
|
174
174
|
${repeat(items, item => item.key, item => html`
|
|
175
175
|
${this._renderListItem(item)}
|
|
@@ -268,7 +268,6 @@ class ListDemoNested extends LitElement {
|
|
|
268
268
|
<d2l-pager-load-more slot="pager"
|
|
269
269
|
@d2l-pager-load-more="${this._handlePagerLoadMore}"
|
|
270
270
|
?has-more="${this._lastItemLoadedIndex < this._items.length - 1}"
|
|
271
|
-
item-count="${this._items.length}"
|
|
272
271
|
page-size="${this._remainingItemCount < this._pageSize ? this._remainingItemCount : this._pageSize}">
|
|
273
272
|
</d2l-pager-load-more>
|
|
274
273
|
`;
|
|
@@ -201,7 +201,6 @@ class DemoList extends LitElement {
|
|
|
201
201
|
<d2l-pager-load-more slot="pager"
|
|
202
202
|
@d2l-pager-load-more="${this._handlePagerLoadMore}"
|
|
203
203
|
?has-more="${this._lastItemLoadedIndex < this.items.length - 1}"
|
|
204
|
-
item-count="${this.items.length}"
|
|
205
204
|
page-size="${remainingItemCount < this._pageSize ? remainingItemCount : this._pageSize}">
|
|
206
205
|
</d2l-pager-load-more>
|
|
207
206
|
</d2l-list>
|
package/components/list/list.js
CHANGED
|
@@ -64,8 +64,6 @@ class List extends PageableMixin(SelectionMixin(LitElement)) {
|
|
|
64
64
|
this.dragMultiple = false;
|
|
65
65
|
this.extendSeparators = false;
|
|
66
66
|
this.grid = false;
|
|
67
|
-
this._itemsShowingCount = 0;
|
|
68
|
-
this._itemsShowingTotalCount = 0;
|
|
69
67
|
this._listItemChanges = [];
|
|
70
68
|
this._childHasExpandCollapseToggle = false;
|
|
71
69
|
|
|
@@ -77,7 +75,7 @@ class List extends PageableMixin(SelectionMixin(LitElement)) {
|
|
|
77
75
|
|
|
78
76
|
connectedCallback() {
|
|
79
77
|
super.connectedCallback();
|
|
80
|
-
this.addEventListener('d2l-list-
|
|
78
|
+
this.addEventListener('d2l-list-item-showing-count-change', this._handleListItemShowingCountChange);
|
|
81
79
|
this.addEventListener('d2l-list-item-nested-change', (e) => this._handleListIemNestedChange(e));
|
|
82
80
|
}
|
|
83
81
|
|
|
@@ -190,13 +188,8 @@ class List extends PageableMixin(SelectionMixin(LitElement)) {
|
|
|
190
188
|
return items[index];
|
|
191
189
|
}
|
|
192
190
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
else return this._getListItemsShowingTotalCount(false);
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
_getLastItemIndex() {
|
|
199
|
-
return this._itemsShowingCount - 1;
|
|
191
|
+
_getItemShowingCount() {
|
|
192
|
+
return this.getItems().length;
|
|
200
193
|
}
|
|
201
194
|
|
|
202
195
|
_getLazyLoadItems() {
|
|
@@ -204,13 +197,6 @@ class List extends PageableMixin(SelectionMixin(LitElement)) {
|
|
|
204
197
|
return items.length > 0 ? items[0]._getFlattenedListItems().lazyLoadListItems : new Map();
|
|
205
198
|
}
|
|
206
199
|
|
|
207
|
-
async _getListItemsShowingTotalCount(refresh) {
|
|
208
|
-
if (refresh) {
|
|
209
|
-
this._itemsShowingTotalCount = this.getItems().length;
|
|
210
|
-
}
|
|
211
|
-
return this._itemsShowingTotalCount;
|
|
212
|
-
}
|
|
213
|
-
|
|
214
200
|
_handleKeyDown(e) {
|
|
215
201
|
if (!this.grid || this.slot === 'nested' || e.keyCode !== keyCodes.TAB) return;
|
|
216
202
|
e.preventDefault();
|
|
@@ -236,33 +222,26 @@ class List extends PageableMixin(SelectionMixin(LitElement)) {
|
|
|
236
222
|
this._listChildrenUpdatedSubscribers.updateSubscribers();
|
|
237
223
|
}
|
|
238
224
|
|
|
239
|
-
|
|
225
|
+
_handleListItemShowingCountChange() {
|
|
240
226
|
if (this.slot === 'nested') return;
|
|
241
227
|
|
|
242
228
|
// debounce the updates for first render case
|
|
243
|
-
if (this.
|
|
244
|
-
|
|
245
|
-
this.
|
|
246
|
-
setTimeout(
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
if (oldCount !== newCount) this._updatePagerCount(newCount);
|
|
250
|
-
this._updateItemsShowingTotalCountRequested = false;
|
|
229
|
+
if (this._updateItemShowingCountRequested) return;
|
|
230
|
+
|
|
231
|
+
this._updateItemShowingCountRequested = true;
|
|
232
|
+
setTimeout(() => {
|
|
233
|
+
this._updateItemShowingCount();
|
|
234
|
+
this._updateItemShowingCountRequested = false;
|
|
251
235
|
}, 0);
|
|
252
236
|
}
|
|
253
237
|
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
if (this._itemsShowingCount === items.length) return;
|
|
257
|
-
this._itemsShowingCount = items.length;
|
|
258
|
-
|
|
259
|
-
this._updatePagerCount(await this._getListItemsShowingTotalCount(true));
|
|
238
|
+
_handleSlotChange() {
|
|
239
|
+
this._updateItemShowingCount();
|
|
260
240
|
|
|
261
241
|
/** @ignore */
|
|
262
|
-
this.dispatchEvent(new CustomEvent('d2l-list-
|
|
242
|
+
this.dispatchEvent(new CustomEvent('d2l-list-item-showing-count-change', {
|
|
263
243
|
bubbles: true,
|
|
264
|
-
composed: true
|
|
265
|
-
detail: { count: this._itemsShowingCount }
|
|
244
|
+
composed: true
|
|
266
245
|
}));
|
|
267
246
|
}
|
|
268
247
|
|
|
@@ -7,16 +7,9 @@ The paging components and mixins can be used to provide consistent paging functi
|
|
|
7
7
|
<script type="module">
|
|
8
8
|
import '@brightspace-ui/core/components/paging/pager-load-more.js';
|
|
9
9
|
</script>
|
|
10
|
-
<d2l-pager-load-more has-more page-size="3"
|
|
10
|
+
<d2l-pager-load-more has-more page-size="3"></d2l-pager-load-more>
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
-
## Best Practices
|
|
14
|
-
<!-- docs: start best practices -->
|
|
15
|
-
<!-- docs: start dos -->
|
|
16
|
-
* Consider the performance impact of acquiring the optional total `item-count`. The `item-count` provides useful context for the user, but counting large numbers of rows can be detrimental to performance. As a very general guide, when the total number of rows that needs to be counted is < 50,000, it's not a performance concern.
|
|
17
|
-
<!-- docs: end dos -->
|
|
18
|
-
<!-- docs: end best practices -->
|
|
19
|
-
|
|
20
13
|
## Load More Paging [d2l-pager-load-more]
|
|
21
14
|
|
|
22
15
|
The `d2l-pager-load-more` component can be used in conjunction with pageable components such as `d2l-list` to provide load-more paging functionality. The pager will dispatch the `d2l-pager-load-more` when clicked, and then the consumer handles the event by loading more items, updating the pager state, and signalling completion by calling `complete()` on the event detail. Focus will be automatically moved on the first new item once complete.
|
|
@@ -24,10 +17,10 @@ The `d2l-pager-load-more` component can be used in conjunction with pageable com
|
|
|
24
17
|
See [Pageable Lists](../../components/list/#pageable-lists).
|
|
25
18
|
|
|
26
19
|
```html
|
|
27
|
-
<d2l-list>
|
|
20
|
+
<d2l-list item-count="85">
|
|
28
21
|
<d2l-list-item ...></d2l-list-item>
|
|
29
22
|
<d2l-list-item ...></d2l-list-item>
|
|
30
|
-
<d2l-pager-load-more slot="pager" has-more page-size="10"
|
|
23
|
+
<d2l-pager-load-more slot="pager" has-more page-size="10"></d2l-pager-load-more>
|
|
31
24
|
</d2l-list>
|
|
32
25
|
```
|
|
33
26
|
|
|
@@ -44,7 +37,6 @@ pager.addEventListener('d2l-pager-load-more', e => {
|
|
|
44
37
|
| Property | Type | Description |
|
|
45
38
|
|---|---|---|
|
|
46
39
|
| `has-more` | Boolean, default: `false` | Whether there are more items that can be loaded. |
|
|
47
|
-
| `item-count` | Number | Total number of items. If not specified, neither it nor the count of items showing will be displayed. |
|
|
48
40
|
| `page-size` | Number, default: 50 | The number of additional items to load. |
|
|
49
41
|
|
|
50
42
|
### Events
|
|
@@ -27,12 +27,12 @@
|
|
|
27
27
|
|
|
28
28
|
<d2l-demo-snippet>
|
|
29
29
|
<template>
|
|
30
|
-
<d2l-test-pageable>
|
|
30
|
+
<d2l-test-pageable item-count="12">
|
|
31
31
|
<ul>
|
|
32
32
|
<li><a href="https://some-website">item 1</a></li>
|
|
33
33
|
<li><a href="https://some-website">item 2</a></li>
|
|
34
34
|
</ul>
|
|
35
|
-
<d2l-pager-load-more id="pager1" slot="pager" has-more page-size="3"
|
|
35
|
+
<d2l-pager-load-more id="pager1" slot="pager" has-more page-size="3"></d2l-pager-load-more>
|
|
36
36
|
</d2l-test-pageable>
|
|
37
37
|
<script>
|
|
38
38
|
document.querySelector('#pager1').addEventListener('d2l-pager-load-more', window.handleLoadMore);
|
|
@@ -1,35 +1,62 @@
|
|
|
1
|
+
import { CollectionMixin } from '../../mixins/collection/collection-mixin.js';
|
|
1
2
|
import { html } from 'lit';
|
|
3
|
+
import { SubscriberRegistryController } from '../../controllers/subscriber/subscriberControllers.js';
|
|
2
4
|
|
|
3
|
-
export const PageableMixin = superclass => class extends superclass {
|
|
5
|
+
export const PageableMixin = superclass => class extends CollectionMixin(superclass) {
|
|
6
|
+
|
|
7
|
+
static get properties() {
|
|
8
|
+
return {
|
|
9
|
+
_itemShowingCount: { state: true },
|
|
10
|
+
};
|
|
11
|
+
}
|
|
4
12
|
|
|
5
13
|
constructor() {
|
|
6
14
|
super();
|
|
7
|
-
|
|
15
|
+
|
|
16
|
+
this._itemShowingCount = 0;
|
|
17
|
+
this._pageableSubscriberRegistry = new SubscriberRegistryController(this, 'pageable', {
|
|
18
|
+
onSubscribe: this._updatePageableSubscriber.bind(this),
|
|
19
|
+
updateSubscribers: this._updatePageableSubscribers.bind(this)
|
|
20
|
+
});
|
|
8
21
|
}
|
|
9
22
|
|
|
10
|
-
|
|
11
|
-
|
|
23
|
+
firstUpdated(changedProperties) {
|
|
24
|
+
super.firstUpdated(changedProperties);
|
|
25
|
+
this._updateItemShowingCount();
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
updated(changedProperties) {
|
|
29
|
+
super.updated(changedProperties);
|
|
30
|
+
|
|
31
|
+
if (changedProperties.has('itemCount') || changedProperties.has('_itemShowingCount')) {
|
|
32
|
+
this._pageableSubscriberRegistry.updateSubscribers();
|
|
33
|
+
}
|
|
34
|
+
}
|
|
12
35
|
|
|
13
36
|
/* must be implemented by consumer */
|
|
14
|
-
|
|
37
|
+
_getItemByIndex(index) { } // eslint-disable-line no-unused-vars
|
|
15
38
|
|
|
16
39
|
/* must be implemented by consumer */
|
|
17
|
-
|
|
40
|
+
_getItemShowingCount() { }
|
|
18
41
|
|
|
19
|
-
|
|
20
|
-
|
|
42
|
+
_getLastItemIndex() {
|
|
43
|
+
return this._itemShowingCount - 1;
|
|
21
44
|
}
|
|
22
45
|
|
|
23
46
|
_renderPagerContainer() {
|
|
24
|
-
return html`<slot name="pager"
|
|
47
|
+
return html`<slot name="pager"></slot>`;
|
|
25
48
|
}
|
|
26
49
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
}
|
|
50
|
+
_updateItemShowingCount() {
|
|
51
|
+
this._itemShowingCount = this._getItemShowingCount();
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
_updatePageableSubscriber(subscriber) {
|
|
55
|
+
subscriber._pageableInfo = { itemShowingCount: this._itemShowingCount, itemCount: this.itemCount };
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
_updatePageableSubscribers(subscribers) {
|
|
59
|
+
subscribers.forEach(subscriber => this._updatePageableSubscriber(subscriber));
|
|
33
60
|
}
|
|
34
61
|
|
|
35
62
|
};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { EventSubscriberController, IdSubscriberController } from '../../controllers/subscriber/subscriberControllers.js';
|
|
2
|
+
|
|
3
|
+
export const PageableSubscriberMixin = superclass => class extends superclass {
|
|
4
|
+
|
|
5
|
+
static get properties() {
|
|
6
|
+
return {
|
|
7
|
+
/**
|
|
8
|
+
* Id of the `PageableMixin` component this component wants to observe (if not located within that component)
|
|
9
|
+
* @type {string}
|
|
10
|
+
*/
|
|
11
|
+
pageableFor: { type: String, reflect: true, attribute: 'pageable-for' },
|
|
12
|
+
_pageableInfo: { state: true }
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
constructor() {
|
|
17
|
+
super();
|
|
18
|
+
|
|
19
|
+
this._pageableInfo = { itemCount: null, itemShowingCount: 0 };
|
|
20
|
+
this._pageableEventSubscriber = new EventSubscriberController(this, 'pageable');
|
|
21
|
+
this._pageableIdSubscriber = new IdSubscriberController(this, 'pageable', { idPropertyName: 'pageableFor' });
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
async getUpdateComplete() {
|
|
25
|
+
await super.getUpdateComplete();
|
|
26
|
+
await (this.pageableFor ? this._pageableIdSubscriber._subscriptionComplete : this._pageableEventSubscriber._subscriptionComplete);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
_getPageableRegistries() {
|
|
30
|
+
return this.pageableFor ? this._pageableIdSubscriber.registries : [ this._pageableEventSubscriber.registry ];
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
};
|
|
@@ -2,7 +2,6 @@ import '../colors/colors.js';
|
|
|
2
2
|
import '../loading-spinner/loading-spinner.js';
|
|
3
3
|
import { css, html, LitElement, nothing } from 'lit';
|
|
4
4
|
import { buttonStyles } from '../button/button-styles.js';
|
|
5
|
-
import { findComposedAncestor } from '../../helpers/dom.js';
|
|
6
5
|
import { FocusMixin } from '../../mixins/focus/focus-mixin.js';
|
|
7
6
|
import { formatNumber } from '@brightspace-ui/intl/lib/number.js';
|
|
8
7
|
import { getFirstFocusableDescendant } from '../../helpers/focus.js';
|
|
@@ -10,6 +9,7 @@ import { getSeparator } from '@brightspace-ui/intl/lib/list.js';
|
|
|
10
9
|
import { labelStyles } from '../typography/styles.js';
|
|
11
10
|
import { LocalizeCoreElement } from '../../helpers/localize-core-element.js';
|
|
12
11
|
import { offscreenStyles } from '../offscreen/offscreen.js';
|
|
12
|
+
import { PageableSubscriberMixin } from './pageable-subscriber-mixin.js';
|
|
13
13
|
|
|
14
14
|
const nativeFocus = document.createElement('div').focus;
|
|
15
15
|
|
|
@@ -17,7 +17,7 @@ const nativeFocus = document.createElement('div').focus;
|
|
|
17
17
|
* A pager component for load-more paging.
|
|
18
18
|
* @fires d2l-pager-load-more - Dispatched when the user clicks the load-more button. Consumers must call the provided "complete" method once items have been loaded.
|
|
19
19
|
*/
|
|
20
|
-
class LoadMore extends FocusMixin(LocalizeCoreElement(LitElement)) {
|
|
20
|
+
class LoadMore extends PageableSubscriberMixin(FocusMixin(LocalizeCoreElement(LitElement))) {
|
|
21
21
|
|
|
22
22
|
static get properties() {
|
|
23
23
|
return {
|
|
@@ -26,21 +26,11 @@ class LoadMore extends FocusMixin(LocalizeCoreElement(LitElement)) {
|
|
|
26
26
|
* @type {boolean}
|
|
27
27
|
*/
|
|
28
28
|
hasMore: { type: Boolean, attribute: 'has-more', reflect: true },
|
|
29
|
-
/**
|
|
30
|
-
* Total number of items. If not specified, neither it nor the count of items showing will be displayed.
|
|
31
|
-
* @type {number}
|
|
32
|
-
*/
|
|
33
|
-
itemCount: { type: Number, attribute: 'item-count', reflect: true },
|
|
34
29
|
/**
|
|
35
30
|
* The number of additional items to load.
|
|
36
31
|
* @type {number}
|
|
37
32
|
*/
|
|
38
33
|
pageSize: { type: Number, attribute: 'page-size', reflect: true },
|
|
39
|
-
/**
|
|
40
|
-
* The number of items showing. Assigned by PageableMixin.
|
|
41
|
-
* @ignore
|
|
42
|
-
*/
|
|
43
|
-
itemShowingCount: { attribute: false, type: Number },
|
|
44
34
|
_loading: { state: true }
|
|
45
35
|
};
|
|
46
36
|
}
|
|
@@ -85,9 +75,8 @@ class LoadMore extends FocusMixin(LocalizeCoreElement(LitElement)) {
|
|
|
85
75
|
constructor() {
|
|
86
76
|
super();
|
|
87
77
|
this.hasMore = false;
|
|
88
|
-
|
|
78
|
+
|
|
89
79
|
/** @ignore */
|
|
90
|
-
this.itemShowingCount = 0;
|
|
91
80
|
this.pageSize = 50;
|
|
92
81
|
this._loading = false;
|
|
93
82
|
}
|
|
@@ -97,7 +86,9 @@ class LoadMore extends FocusMixin(LocalizeCoreElement(LitElement)) {
|
|
|
97
86
|
}
|
|
98
87
|
|
|
99
88
|
render() {
|
|
100
|
-
if (!this.hasMore) return;
|
|
89
|
+
if (!this.hasMore) return nothing;
|
|
90
|
+
const { itemCount, itemShowingCount } = this._pageableInfo;
|
|
91
|
+
|
|
101
92
|
return html`
|
|
102
93
|
${this._loading ? html`
|
|
103
94
|
<span class="d2l-offscreen" role="alert">${this.localize('components.pager-load-more.status-loading')}</span>
|
|
@@ -107,10 +98,10 @@ class LoadMore extends FocusMixin(LocalizeCoreElement(LitElement)) {
|
|
|
107
98
|
<d2l-loading-spinner size="24"></d2l-loading-spinner>
|
|
108
99
|
` : html`
|
|
109
100
|
<span class="action">${this.localize('components.pager-load-more.action', { count: formatNumber(this.pageSize) })}</span>
|
|
110
|
-
${
|
|
101
|
+
${itemCount !== null ? html`
|
|
111
102
|
<span class="d2l-offscreen">${getSeparator({ nonBreaking: true })}</span>
|
|
112
103
|
<span class="separator"></span>
|
|
113
|
-
<span class="info">${this.localize('components.pager-load-more.info', { showingCount: formatNumber(
|
|
104
|
+
<span class="info">${this.localize('components.pager-load-more.info', { showingCount: formatNumber(itemShowingCount), totalCount: itemCount, totalCountFormatted: formatNumber(itemCount) })}</span>
|
|
114
105
|
` : nothing}
|
|
115
106
|
`}
|
|
116
107
|
</button>
|
|
@@ -119,7 +110,7 @@ class LoadMore extends FocusMixin(LocalizeCoreElement(LitElement)) {
|
|
|
119
110
|
|
|
120
111
|
async _handleClick() {
|
|
121
112
|
if (this._loading) return;
|
|
122
|
-
const pageable =
|
|
113
|
+
const pageable = this._getPageableRegistries()[0];
|
|
123
114
|
if (!pageable) return;
|
|
124
115
|
const lastItemIndex = pageable._getLastItemIndex();
|
|
125
116
|
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { CollectionMixin } from '../../mixins/collection/collection-mixin.js';
|
|
1
2
|
import { RtlMixin } from '../../mixins/rtl/rtl-mixin.js';
|
|
2
3
|
|
|
3
4
|
const keyCodes = {
|
|
@@ -35,15 +36,10 @@ export class SelectionInfo {
|
|
|
35
36
|
|
|
36
37
|
}
|
|
37
38
|
|
|
38
|
-
export const SelectionMixin = superclass => class extends RtlMixin(superclass) {
|
|
39
|
+
export const SelectionMixin = superclass => class extends RtlMixin(CollectionMixin(superclass)) {
|
|
39
40
|
|
|
40
41
|
static get properties() {
|
|
41
42
|
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' },
|
|
47
43
|
/**
|
|
48
44
|
* 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.
|
|
49
45
|
* @type {boolean}
|
|
@@ -59,7 +55,6 @@ export const SelectionMixin = superclass => class extends RtlMixin(superclass) {
|
|
|
59
55
|
|
|
60
56
|
constructor() {
|
|
61
57
|
super();
|
|
62
|
-
this.itemCount = 0;
|
|
63
58
|
this.selectionSingle = false;
|
|
64
59
|
this._selectAllPages = false;
|
|
65
60
|
this._selectionObservers = new Map();
|
|
@@ -9,6 +9,7 @@ class BaseController {
|
|
|
9
9
|
this._name = name;
|
|
10
10
|
this._options = options;
|
|
11
11
|
this._eventName = `d2l-subscribe-${this._name}`;
|
|
12
|
+
this._subscriptionComplete = Promise.resolve();
|
|
12
13
|
}
|
|
13
14
|
}
|
|
14
15
|
|
|
@@ -111,7 +112,12 @@ export class EventSubscriberController extends BaseSubscriber {
|
|
|
111
112
|
|
|
112
113
|
hostConnected() {
|
|
113
114
|
// delay subscription otherwise import/upgrade order can cause selection mixin to miss event
|
|
114
|
-
|
|
115
|
+
this._subscriptionComplete = new Promise(resolve => {
|
|
116
|
+
requestAnimationFrame(() => {
|
|
117
|
+
this._subscribe();
|
|
118
|
+
resolve();
|
|
119
|
+
});
|
|
120
|
+
});
|
|
115
121
|
}
|
|
116
122
|
|
|
117
123
|
hostDisconnected() {
|
package/custom-elements.json
CHANGED
|
@@ -449,20 +449,39 @@
|
|
|
449
449
|
"type": "string"
|
|
450
450
|
},
|
|
451
451
|
{
|
|
452
|
-
"name": "disabled-
|
|
453
|
-
"description": "
|
|
454
|
-
"type": "
|
|
452
|
+
"name": "disabled-down",
|
|
453
|
+
"description": "Disables the down interaction",
|
|
454
|
+
"type": "boolean"
|
|
455
|
+
},
|
|
456
|
+
{
|
|
457
|
+
"name": "disabled-end",
|
|
458
|
+
"description": "Disables the end interaction",
|
|
459
|
+
"type": "boolean"
|
|
460
|
+
},
|
|
461
|
+
{
|
|
462
|
+
"name": "disabled-home",
|
|
463
|
+
"description": "Disables the home interaction",
|
|
464
|
+
"type": "boolean"
|
|
465
|
+
},
|
|
466
|
+
{
|
|
467
|
+
"name": "disabled-left",
|
|
468
|
+
"description": "Disables the left interaction",
|
|
469
|
+
"type": "boolean"
|
|
470
|
+
},
|
|
471
|
+
{
|
|
472
|
+
"name": "disabled-right",
|
|
473
|
+
"description": "Disables the right interaction",
|
|
474
|
+
"type": "boolean"
|
|
475
|
+
},
|
|
476
|
+
{
|
|
477
|
+
"name": "disabled-up",
|
|
478
|
+
"description": "Disables the up interaction",
|
|
479
|
+
"type": "boolean"
|
|
455
480
|
},
|
|
456
481
|
{
|
|
457
482
|
"name": "text",
|
|
458
483
|
"description": "REQUIRED: Accessible text for the button",
|
|
459
484
|
"type": "string"
|
|
460
|
-
},
|
|
461
|
-
{
|
|
462
|
-
"name": "disabled",
|
|
463
|
-
"description": "Disables the button",
|
|
464
|
-
"type": "boolean",
|
|
465
|
-
"default": "false"
|
|
466
485
|
}
|
|
467
486
|
],
|
|
468
487
|
"properties": [
|
|
@@ -473,23 +492,46 @@
|
|
|
473
492
|
"type": "string"
|
|
474
493
|
},
|
|
475
494
|
{
|
|
476
|
-
"name": "
|
|
477
|
-
"attribute": "disabled-
|
|
478
|
-
"description": "
|
|
479
|
-
"type": "
|
|
495
|
+
"name": "disabledDown",
|
|
496
|
+
"attribute": "disabled-down",
|
|
497
|
+
"description": "Disables the down interaction",
|
|
498
|
+
"type": "boolean"
|
|
499
|
+
},
|
|
500
|
+
{
|
|
501
|
+
"name": "disabledEnd",
|
|
502
|
+
"attribute": "disabled-end",
|
|
503
|
+
"description": "Disables the end interaction",
|
|
504
|
+
"type": "boolean"
|
|
505
|
+
},
|
|
506
|
+
{
|
|
507
|
+
"name": "disabledHome",
|
|
508
|
+
"attribute": "disabled-home",
|
|
509
|
+
"description": "Disables the home interaction",
|
|
510
|
+
"type": "boolean"
|
|
511
|
+
},
|
|
512
|
+
{
|
|
513
|
+
"name": "disabledLeft",
|
|
514
|
+
"attribute": "disabled-left",
|
|
515
|
+
"description": "Disables the left interaction",
|
|
516
|
+
"type": "boolean"
|
|
517
|
+
},
|
|
518
|
+
{
|
|
519
|
+
"name": "disabledRight",
|
|
520
|
+
"attribute": "disabled-right",
|
|
521
|
+
"description": "Disables the right interaction",
|
|
522
|
+
"type": "boolean"
|
|
523
|
+
},
|
|
524
|
+
{
|
|
525
|
+
"name": "disabledUp",
|
|
526
|
+
"attribute": "disabled-up",
|
|
527
|
+
"description": "Disables the up interaction",
|
|
528
|
+
"type": "boolean"
|
|
480
529
|
},
|
|
481
530
|
{
|
|
482
531
|
"name": "text",
|
|
483
532
|
"attribute": "text",
|
|
484
533
|
"description": "REQUIRED: Accessible text for the button",
|
|
485
534
|
"type": "string"
|
|
486
|
-
},
|
|
487
|
-
{
|
|
488
|
-
"name": "disabled",
|
|
489
|
-
"attribute": "disabled",
|
|
490
|
-
"description": "Disables the button",
|
|
491
|
-
"type": "boolean",
|
|
492
|
-
"default": "false"
|
|
493
535
|
}
|
|
494
536
|
],
|
|
495
537
|
"events": [
|
|
@@ -8822,15 +8864,14 @@
|
|
|
8822
8864
|
"default": "false"
|
|
8823
8865
|
},
|
|
8824
8866
|
{
|
|
8825
|
-
"name": "
|
|
8826
|
-
"description": "
|
|
8867
|
+
"name": "item-count",
|
|
8868
|
+
"description": "Total number of items. If not specified, features like select-all-pages will be disabled.",
|
|
8827
8869
|
"type": "number"
|
|
8828
8870
|
},
|
|
8829
8871
|
{
|
|
8830
|
-
"name": "
|
|
8831
|
-
"description": "
|
|
8832
|
-
"type": "number"
|
|
8833
|
-
"default": "0"
|
|
8872
|
+
"name": "selection-count-override",
|
|
8873
|
+
"description": "ADVANCED: Temporary optional parameter used to override existing count. Will be removed soon, use with caution.",
|
|
8874
|
+
"type": "number"
|
|
8834
8875
|
},
|
|
8835
8876
|
{
|
|
8836
8877
|
"name": "selection-single",
|
|
@@ -8868,19 +8909,18 @@
|
|
|
8868
8909
|
"type": "boolean",
|
|
8869
8910
|
"default": "false"
|
|
8870
8911
|
},
|
|
8912
|
+
{
|
|
8913
|
+
"name": "itemCount",
|
|
8914
|
+
"attribute": "item-count",
|
|
8915
|
+
"description": "Total number of items. If not specified, features like select-all-pages will be disabled.",
|
|
8916
|
+
"type": "number"
|
|
8917
|
+
},
|
|
8871
8918
|
{
|
|
8872
8919
|
"name": "selectionCountOverride",
|
|
8873
8920
|
"attribute": "selection-count-override",
|
|
8874
8921
|
"description": "ADVANCED: Temporary optional parameter used to override existing count. Will be removed soon, use with caution.",
|
|
8875
8922
|
"type": "number"
|
|
8876
8923
|
},
|
|
8877
|
-
{
|
|
8878
|
-
"name": "itemCount",
|
|
8879
|
-
"attribute": "item-count",
|
|
8880
|
-
"description": "Total number of items. Required when selecting all pages is allowed.",
|
|
8881
|
-
"type": "number",
|
|
8882
|
-
"default": "0"
|
|
8883
|
-
},
|
|
8884
8924
|
{
|
|
8885
8925
|
"name": "selectionSingle",
|
|
8886
8926
|
"attribute": "selection-single",
|
|
@@ -10017,6 +10057,11 @@
|
|
|
10017
10057
|
"path": "./components/paging/pager-load-more.js",
|
|
10018
10058
|
"description": "A pager component for load-more paging.",
|
|
10019
10059
|
"attributes": [
|
|
10060
|
+
{
|
|
10061
|
+
"name": "page-size",
|
|
10062
|
+
"description": "The number of additional items to load.",
|
|
10063
|
+
"type": "number"
|
|
10064
|
+
},
|
|
10020
10065
|
{
|
|
10021
10066
|
"name": "has-more",
|
|
10022
10067
|
"description": "Whether there are more items that can be loaded.",
|
|
@@ -10024,19 +10069,18 @@
|
|
|
10024
10069
|
"default": "false"
|
|
10025
10070
|
},
|
|
10026
10071
|
{
|
|
10027
|
-
"name": "
|
|
10028
|
-
"description": "
|
|
10029
|
-
"type": "
|
|
10030
|
-
"default": "-1"
|
|
10031
|
-
},
|
|
10032
|
-
{
|
|
10033
|
-
"name": "page-size",
|
|
10034
|
-
"description": "The number of additional items to load.",
|
|
10035
|
-
"type": "number",
|
|
10036
|
-
"default": "50"
|
|
10072
|
+
"name": "pageable-for",
|
|
10073
|
+
"description": "Id of the `PageableMixin` component this component wants to observe (if not located within that component)",
|
|
10074
|
+
"type": "string"
|
|
10037
10075
|
}
|
|
10038
10076
|
],
|
|
10039
10077
|
"properties": [
|
|
10078
|
+
{
|
|
10079
|
+
"name": "pageSize",
|
|
10080
|
+
"attribute": "page-size",
|
|
10081
|
+
"description": "The number of additional items to load.",
|
|
10082
|
+
"type": "number"
|
|
10083
|
+
},
|
|
10040
10084
|
{
|
|
10041
10085
|
"name": "hasMore",
|
|
10042
10086
|
"attribute": "has-more",
|
|
@@ -10045,18 +10089,10 @@
|
|
|
10045
10089
|
"default": "false"
|
|
10046
10090
|
},
|
|
10047
10091
|
{
|
|
10048
|
-
"name": "
|
|
10049
|
-
"attribute": "
|
|
10050
|
-
"description": "
|
|
10051
|
-
"type": "
|
|
10052
|
-
"default": "-1"
|
|
10053
|
-
},
|
|
10054
|
-
{
|
|
10055
|
-
"name": "pageSize",
|
|
10056
|
-
"attribute": "page-size",
|
|
10057
|
-
"description": "The number of additional items to load.",
|
|
10058
|
-
"type": "number",
|
|
10059
|
-
"default": "50"
|
|
10092
|
+
"name": "pageableFor",
|
|
10093
|
+
"attribute": "pageable-for",
|
|
10094
|
+
"description": "Id of the `PageableMixin` component this component wants to observe (if not located within that component)",
|
|
10095
|
+
"type": "string"
|
|
10060
10096
|
},
|
|
10061
10097
|
{
|
|
10062
10098
|
"name": "documentLocaleSettings",
|
|
@@ -10072,7 +10108,41 @@
|
|
|
10072
10108
|
},
|
|
10073
10109
|
{
|
|
10074
10110
|
"name": "d2l-test-pageable",
|
|
10075
|
-
"path": "./components/paging/test/pageable-component.js"
|
|
10111
|
+
"path": "./components/paging/test/pageable-component.js",
|
|
10112
|
+
"attributes": [
|
|
10113
|
+
{
|
|
10114
|
+
"name": "item-count",
|
|
10115
|
+
"description": "Total number of items. If not specified, features like select-all-pages will be disabled.",
|
|
10116
|
+
"type": "number"
|
|
10117
|
+
}
|
|
10118
|
+
],
|
|
10119
|
+
"properties": [
|
|
10120
|
+
{
|
|
10121
|
+
"name": "itemCount",
|
|
10122
|
+
"attribute": "item-count",
|
|
10123
|
+
"description": "Total number of items. If not specified, features like select-all-pages will be disabled.",
|
|
10124
|
+
"type": "number"
|
|
10125
|
+
}
|
|
10126
|
+
]
|
|
10127
|
+
},
|
|
10128
|
+
{
|
|
10129
|
+
"name": "d2l-test-pageable-simple",
|
|
10130
|
+
"path": "./components/paging/test/pageable-component.js",
|
|
10131
|
+
"attributes": [
|
|
10132
|
+
{
|
|
10133
|
+
"name": "item-count",
|
|
10134
|
+
"description": "Total number of items. If not specified, features like select-all-pages will be disabled.",
|
|
10135
|
+
"type": "number"
|
|
10136
|
+
}
|
|
10137
|
+
],
|
|
10138
|
+
"properties": [
|
|
10139
|
+
{
|
|
10140
|
+
"name": "itemCount",
|
|
10141
|
+
"attribute": "item-count",
|
|
10142
|
+
"description": "Total number of items. If not specified, features like select-all-pages will be disabled.",
|
|
10143
|
+
"type": "number"
|
|
10144
|
+
}
|
|
10145
|
+
]
|
|
10076
10146
|
},
|
|
10077
10147
|
{
|
|
10078
10148
|
"name": "d2l-test-scroll-wrapper",
|
|
@@ -10152,12 +10222,6 @@
|
|
|
10152
10222
|
"description": "ADVANCED: Temporary optional parameter used to override existing count. Will be removed soon, use with caution.",
|
|
10153
10223
|
"type": "number"
|
|
10154
10224
|
},
|
|
10155
|
-
{
|
|
10156
|
-
"name": "item-count",
|
|
10157
|
-
"description": "Total number of items. Required when selecting all pages is allowed.",
|
|
10158
|
-
"type": "number",
|
|
10159
|
-
"default": "0"
|
|
10160
|
-
},
|
|
10161
10225
|
{
|
|
10162
10226
|
"name": "selection-single",
|
|
10163
10227
|
"description": "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.",
|
|
@@ -10172,13 +10236,6 @@
|
|
|
10172
10236
|
"description": "ADVANCED: Temporary optional parameter used to override existing count. Will be removed soon, use with caution.",
|
|
10173
10237
|
"type": "number"
|
|
10174
10238
|
},
|
|
10175
|
-
{
|
|
10176
|
-
"name": "itemCount",
|
|
10177
|
-
"attribute": "item-count",
|
|
10178
|
-
"description": "Total number of items. Required when selecting all pages is allowed.",
|
|
10179
|
-
"type": "number",
|
|
10180
|
-
"default": "0"
|
|
10181
|
-
},
|
|
10182
10239
|
{
|
|
10183
10240
|
"name": "selectionSingle",
|
|
10184
10241
|
"attribute": "selection-single",
|
|
@@ -10801,12 +10858,6 @@
|
|
|
10801
10858
|
"description": "ADVANCED: Temporary optional parameter used to override existing count. Will be removed soon, use with caution.",
|
|
10802
10859
|
"type": "number"
|
|
10803
10860
|
},
|
|
10804
|
-
{
|
|
10805
|
-
"name": "item-count",
|
|
10806
|
-
"description": "Total number of items. Required when selecting all pages is allowed.",
|
|
10807
|
-
"type": "number",
|
|
10808
|
-
"default": "0"
|
|
10809
|
-
},
|
|
10810
10861
|
{
|
|
10811
10862
|
"name": "selection-single",
|
|
10812
10863
|
"description": "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.",
|
|
@@ -10821,13 +10872,6 @@
|
|
|
10821
10872
|
"description": "ADVANCED: Temporary optional parameter used to override existing count. Will be removed soon, use with caution.",
|
|
10822
10873
|
"type": "number"
|
|
10823
10874
|
},
|
|
10824
|
-
{
|
|
10825
|
-
"name": "itemCount",
|
|
10826
|
-
"attribute": "item-count",
|
|
10827
|
-
"description": "Total number of items. Required when selecting all pages is allowed.",
|
|
10828
|
-
"type": "number",
|
|
10829
|
-
"default": "0"
|
|
10830
|
-
},
|
|
10831
10875
|
{
|
|
10832
10876
|
"name": "selectionSingle",
|
|
10833
10877
|
"attribute": "selection-single",
|
|
@@ -11329,12 +11373,6 @@
|
|
|
11329
11373
|
"description": "ADVANCED: Temporary optional parameter used to override existing count. Will be removed soon, use with caution.",
|
|
11330
11374
|
"type": "number"
|
|
11331
11375
|
},
|
|
11332
|
-
{
|
|
11333
|
-
"name": "item-count",
|
|
11334
|
-
"description": "Total number of items. Required when selecting all pages is allowed.",
|
|
11335
|
-
"type": "number",
|
|
11336
|
-
"default": "0"
|
|
11337
|
-
},
|
|
11338
11376
|
{
|
|
11339
11377
|
"name": "selection-single",
|
|
11340
11378
|
"description": "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.",
|
|
@@ -11380,13 +11418,6 @@
|
|
|
11380
11418
|
"description": "ADVANCED: Temporary optional parameter used to override existing count. Will be removed soon, use with caution.",
|
|
11381
11419
|
"type": "number"
|
|
11382
11420
|
},
|
|
11383
|
-
{
|
|
11384
|
-
"name": "itemCount",
|
|
11385
|
-
"attribute": "item-count",
|
|
11386
|
-
"description": "Total number of items. Required when selecting all pages is allowed.",
|
|
11387
|
-
"type": "number",
|
|
11388
|
-
"default": "0"
|
|
11389
|
-
},
|
|
11390
11421
|
{
|
|
11391
11422
|
"name": "selectionSingle",
|
|
11392
11423
|
"attribute": "selection-single",
|
|
@@ -11552,12 +11583,6 @@
|
|
|
11552
11583
|
"description": "ADVANCED: Temporary optional parameter used to override existing count. Will be removed soon, use with caution.",
|
|
11553
11584
|
"type": "number"
|
|
11554
11585
|
},
|
|
11555
|
-
{
|
|
11556
|
-
"name": "item-count",
|
|
11557
|
-
"description": "Total number of items. Required when selecting all pages is allowed.",
|
|
11558
|
-
"type": "number",
|
|
11559
|
-
"default": "0"
|
|
11560
|
-
},
|
|
11561
11586
|
{
|
|
11562
11587
|
"name": "selection-single",
|
|
11563
11588
|
"description": "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.",
|
|
@@ -11593,13 +11618,6 @@
|
|
|
11593
11618
|
"description": "ADVANCED: Temporary optional parameter used to override existing count. Will be removed soon, use with caution.",
|
|
11594
11619
|
"type": "number"
|
|
11595
11620
|
},
|
|
11596
|
-
{
|
|
11597
|
-
"name": "itemCount",
|
|
11598
|
-
"attribute": "item-count",
|
|
11599
|
-
"description": "Total number of items. Required when selecting all pages is allowed.",
|
|
11600
|
-
"type": "number",
|
|
11601
|
-
"default": "0"
|
|
11602
|
-
},
|
|
11603
11621
|
{
|
|
11604
11622
|
"name": "selectionSingle",
|
|
11605
11623
|
"attribute": "selection-single",
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# CollectionMixin
|
|
2
|
+
|
|
3
|
+
The `CollectionMixin` describes a collection of items like a list or table. It has one attribute, `item-count`, which optionally defines the total number of items in the collection. This may be greater than the number of items currently displayed, and is useful for actions like select-all and paging.
|
|
4
|
+
|
|
5
|
+
## Best Practices
|
|
6
|
+
<!-- docs: start best practices -->
|
|
7
|
+
<!-- docs: start dos -->
|
|
8
|
+
* Consider the performance impact of acquiring the optional total `item-count`. The `item-count` provides useful context for the user, but counting large numbers of rows can be detrimental to performance. As a very general guide, when the total number of rows that needs to be counted is < 50,000, it's not a performance concern.
|
|
9
|
+
<!-- docs: end dos -->
|
|
10
|
+
<!-- docs: end best practices -->
|
|
11
|
+
|
|
12
|
+
## Usage
|
|
13
|
+
|
|
14
|
+
Apply the mixin and access the `itemCount` property as needed. Note that `itemCount` has a default value of `null` to indicate that no count was specified.
|
|
15
|
+
|
|
16
|
+
```js
|
|
17
|
+
import { CollectionMixin } from '@brightspace-ui/core/mixins/collection-mixin.js';
|
|
18
|
+
|
|
19
|
+
class MyComponent extends CollectionMixin(LitElement) {
|
|
20
|
+
render() {
|
|
21
|
+
const itemCountToDisplay = this.itemCount !== null ? this.itemCount : 'Unspecified';
|
|
22
|
+
return html`
|
|
23
|
+
<p>Total number of items: ${itemCountToDisplay}</p>
|
|
24
|
+
<slot></slot>
|
|
25
|
+
`;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
<!-- docs: start hidden content -->
|
|
31
|
+
### Properties
|
|
32
|
+
|
|
33
|
+
| Property | Type | Description |
|
|
34
|
+
|---|---|---|
|
|
35
|
+
| `item-count` | Number | Total number of items. Required when selecting all pages is allowed. |
|
|
36
|
+
<!-- docs: end hidden content -->
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export const CollectionMixin = superclass => class extends superclass {
|
|
2
|
+
|
|
3
|
+
static get properties() {
|
|
4
|
+
return {
|
|
5
|
+
/**
|
|
6
|
+
* Total number of items. If not specified, features like select-all-pages will be disabled.
|
|
7
|
+
* @type {number}
|
|
8
|
+
*/
|
|
9
|
+
itemCount: { type: Number, attribute: 'item-count', reflect: true },
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
constructor() {
|
|
14
|
+
super();
|
|
15
|
+
this.itemCount = null;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@brightspace-ui/core",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.106.0",
|
|
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",
|