@brightspace-ui/core 1.217.0 → 1.219.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/components/dropdown/dropdown-content-mixin.js +2 -1
- package/components/filter/README.md +1 -0
- package/components/filter/filter-dimension-set.js +7 -1
- package/components/filter/filter.js +58 -0
- package/components/form/form-element-mixin.js +0 -1
- package/components/html-block/html-block.js +7 -4
- package/components/list/demo/list-item-custom.js +1 -0
- package/components/list/list-item-button-mixin.js +7 -1
- package/components/list/list-item-drag-handle.js +43 -5
- package/components/list/list-item-generic-layout.js +1 -0
- package/components/list/list-item-link-mixin.js +3 -1
- package/components/list/list-item-mixin.js +54 -3
- package/components/list/list-item-role-mixin.js +2 -1
- package/components/menu/menu-item.js +1 -0
- package/controllers/subscriber/README.md +3 -3
- package/controllers/subscriber/subscriberControllers.js +4 -4
- package/custom-elements.json +169 -3
- package/helpers/demo/announce-test.js +1 -1
- package/helpers/mathjax.js +7 -9
- package/lang/ar.js +20 -5
- package/lang/cy.js +20 -5
- package/lang/da.js +20 -5
- package/lang/de.js +20 -5
- package/lang/en.js +16 -0
- package/lang/es-es.js +20 -5
- package/lang/es.js +20 -5
- package/lang/fr-fr.js +20 -5
- package/lang/fr.js +20 -5
- package/lang/ja.js +20 -5
- package/lang/ko.js +20 -5
- package/lang/nl.js +20 -5
- package/lang/pt.js +20 -5
- package/lang/sv.js +20 -5
- package/lang/tr.js +20 -5
- package/lang/zh-tw.js +20 -5
- package/lang/zh.js +20 -5
- package/package.json +2 -2
|
@@ -189,6 +189,7 @@ Set dimension on mobile:
|
|
|
189
189
|
| `select-all` | Boolean | Whether to show a select all checkbox and selection summary for this dimension |
|
|
190
190
|
| `selection-single` | Boolean | Whether only one value can be selected at a time for this dimension |
|
|
191
191
|
| `text` | String, required | Text for the dimension in the menu |
|
|
192
|
+
| `value-only-active-filter-text` | Boolean | Whether to hide the dimension in the text sent to active filter subscribers |
|
|
192
193
|
<!-- docs: end hidden content -->
|
|
193
194
|
|
|
194
195
|
## Filter Dimension: Set Value [d2l-filter-dimension-set-value]
|
|
@@ -38,7 +38,12 @@ class FilterDimensionSet extends LitElement {
|
|
|
38
38
|
* REQUIRED: The text that is displayed for the dimension title
|
|
39
39
|
* @type {string}
|
|
40
40
|
*/
|
|
41
|
-
text: { type: String }
|
|
41
|
+
text: { type: String },
|
|
42
|
+
/**
|
|
43
|
+
* Whether to hide the dimension in the text sent to active filter subscribers
|
|
44
|
+
* @type {boolean}
|
|
45
|
+
*/
|
|
46
|
+
valueOnlyActiveFilterText: { type: Boolean, attribute: 'value-only-active-filter-text' }
|
|
42
47
|
};
|
|
43
48
|
}
|
|
44
49
|
|
|
@@ -49,6 +54,7 @@ class FilterDimensionSet extends LitElement {
|
|
|
49
54
|
this.selectAll = false;
|
|
50
55
|
this.selectionSingle = false;
|
|
51
56
|
this.text = '';
|
|
57
|
+
this.valueOnlyActiveFilterText = false;
|
|
52
58
|
this._slot = null;
|
|
53
59
|
}
|
|
54
60
|
|
|
@@ -23,6 +23,7 @@ import { ifDefined } from 'lit-html/directives/if-defined.js';
|
|
|
23
23
|
import { LocalizeCoreElement } from '../../lang/localize-core-element.js';
|
|
24
24
|
import { offscreenStyles } from '../offscreen/offscreen.js';
|
|
25
25
|
import { RtlMixin } from '../../mixins/rtl-mixin.js';
|
|
26
|
+
import { SubscriberRegistryController } from '../../controllers/subscriber/subscriberControllers.js';
|
|
26
27
|
|
|
27
28
|
const ARROWLEFT_KEY_CODE = 37;
|
|
28
29
|
const ESCAPE_KEY_CODE = 27;
|
|
@@ -143,6 +144,22 @@ class Filter extends LocalizeCoreElement(RtlMixin(LitElement)) {
|
|
|
143
144
|
this._dimensions = [];
|
|
144
145
|
this._openedDimensions = [];
|
|
145
146
|
this._totalAppliedCount = 0;
|
|
147
|
+
|
|
148
|
+
this._activeFilters = null;
|
|
149
|
+
this._activeFiltersSubscribers = new SubscriberRegistryController(this,
|
|
150
|
+
{ onSubscribe: this._updateActiveFiltersSubscriber.bind(this), updateSubscribers: this._updateActiveFiltersSubscribers.bind(this) },
|
|
151
|
+
{}
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
connectedCallback() {
|
|
156
|
+
super.connectedCallback();
|
|
157
|
+
this._activeFiltersSubscribers.hostConnected();
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
disconnectedCallback() {
|
|
161
|
+
super.disconnectedCallback();
|
|
162
|
+
this._activeFiltersSubscribers.hostDisconnected();
|
|
146
163
|
}
|
|
147
164
|
|
|
148
165
|
firstUpdated(changedProperties) {
|
|
@@ -217,6 +234,10 @@ class Filter extends LocalizeCoreElement(RtlMixin(LitElement)) {
|
|
|
217
234
|
if (opener) opener.focus();
|
|
218
235
|
}
|
|
219
236
|
|
|
237
|
+
getSubscriberController() {
|
|
238
|
+
return this._activeFiltersSubscribers;
|
|
239
|
+
}
|
|
240
|
+
|
|
220
241
|
requestFilterClearAll() {
|
|
221
242
|
this._handleClearAll();
|
|
222
243
|
}
|
|
@@ -423,6 +444,8 @@ class Filter extends LocalizeCoreElement(RtlMixin(LitElement)) {
|
|
|
423
444
|
}));
|
|
424
445
|
this._changeEventsToDispatch = new Map();
|
|
425
446
|
this._changeEventTimeout = null;
|
|
447
|
+
|
|
448
|
+
this._activeFiltersSubscribers.updateSubscribers();
|
|
426
449
|
}
|
|
427
450
|
|
|
428
451
|
_dispatchDimensionFirstOpenEvent(key) {
|
|
@@ -511,9 +534,11 @@ class Filter extends LocalizeCoreElement(RtlMixin(LitElement)) {
|
|
|
511
534
|
dimension.appliedCount--;
|
|
512
535
|
this._totalAppliedCount--;
|
|
513
536
|
}
|
|
537
|
+
this._activeFiltersSubscribers.updateSubscribers();
|
|
514
538
|
} else if (prop === 'values') {
|
|
515
539
|
if (dimension.searchValue) shouldSearch = true;
|
|
516
540
|
shouldRecount = true;
|
|
541
|
+
this._activeFiltersSubscribers.updateSubscribers();
|
|
517
542
|
}
|
|
518
543
|
});
|
|
519
544
|
|
|
@@ -609,6 +634,7 @@ class Filter extends LocalizeCoreElement(RtlMixin(LitElement)) {
|
|
|
609
634
|
info.searchType = dimension.searchType;
|
|
610
635
|
info.selectionSingle = dimension.selectionSingle;
|
|
611
636
|
if (dimension.selectAll && !dimension.selectionSingle) info.selectAllIdPrefix = SET_DIMENSION_ID_PREFIX;
|
|
637
|
+
info.valueOnlyActiveFilterText = dimension.valueOnlyActiveFilterText;
|
|
612
638
|
const values = dimension._getValues();
|
|
613
639
|
info.values = values;
|
|
614
640
|
break;
|
|
@@ -619,6 +645,7 @@ class Filter extends LocalizeCoreElement(RtlMixin(LitElement)) {
|
|
|
619
645
|
});
|
|
620
646
|
|
|
621
647
|
this._setFilterCounts();
|
|
648
|
+
this._activeFiltersSubscribers.updateSubscribers();
|
|
622
649
|
}
|
|
623
650
|
|
|
624
651
|
_isDimensionEmpty(dimension) {
|
|
@@ -717,6 +744,37 @@ class Filter extends LocalizeCoreElement(RtlMixin(LitElement)) {
|
|
|
717
744
|
e.stopPropagation();
|
|
718
745
|
}
|
|
719
746
|
|
|
747
|
+
_updateActiveFilters() {
|
|
748
|
+
const activeFilters = [];
|
|
749
|
+
|
|
750
|
+
this._dimensions.forEach(dimension => {
|
|
751
|
+
switch (dimension.type) {
|
|
752
|
+
case 'd2l-filter-dimension-set': {
|
|
753
|
+
dimension.values.forEach(value => {
|
|
754
|
+
if (value.selected) {
|
|
755
|
+
const keyObject = { dimension: dimension.key, value: value.key };
|
|
756
|
+
const text = dimension.valueOnlyActiveFilterText ? value.text : `${dimension.text}: ${value.text}`;
|
|
757
|
+
activeFilters.push({ keyObject: keyObject, text: text });
|
|
758
|
+
}
|
|
759
|
+
});
|
|
760
|
+
break;
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
});
|
|
764
|
+
|
|
765
|
+
this._activeFilters = activeFilters;
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
_updateActiveFiltersSubscriber(subscriber) {
|
|
769
|
+
if (!this._activeFilters) this._updateActiveFilters();
|
|
770
|
+
subscriber.updateActiveFilters(this.id, this._activeFilters);
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
_updateActiveFiltersSubscribers(subscribers) {
|
|
774
|
+
this._updateActiveFilters();
|
|
775
|
+
subscribers.forEach(subscriber => subscriber.updateActiveFilters(this.id, this._activeFilters));
|
|
776
|
+
}
|
|
777
|
+
|
|
720
778
|
}
|
|
721
779
|
|
|
722
780
|
customElements.define('d2l-filter', Filter);
|
|
@@ -88,7 +88,6 @@ export const FormElementMixin = superclass => class extends LocalizeCoreElement(
|
|
|
88
88
|
*/
|
|
89
89
|
invalid: { type: Boolean, reflect: true },
|
|
90
90
|
/**
|
|
91
|
-
* @ignore
|
|
92
91
|
* Name of the form control. Submitted with the form as part of a name/value pair.
|
|
93
92
|
* @type {string}
|
|
94
93
|
*/
|
|
@@ -225,14 +225,17 @@ class HtmlBlock extends LitElement {
|
|
|
225
225
|
|
|
226
226
|
async _processRenderers(elem) {
|
|
227
227
|
for (const renderer of getRenderers()) {
|
|
228
|
-
if (this.noDeferredRendering && !renderer.canRenderInline) continue;
|
|
229
|
-
|
|
230
228
|
if (this._contextObserverController && renderer.contextAttributes) {
|
|
231
229
|
const contextValues = new Map();
|
|
232
230
|
renderer.contextAttributes.forEach(attr => contextValues.set(attr, this._contextObserverController.values.get(attr)));
|
|
233
|
-
elem = await renderer.render(elem,
|
|
231
|
+
elem = await renderer.render(elem, {
|
|
232
|
+
contextValues: contextValues,
|
|
233
|
+
noDeferredRendering: this.noDeferredRendering
|
|
234
|
+
});
|
|
234
235
|
} else {
|
|
235
|
-
elem = await renderer.render(elem
|
|
236
|
+
elem = await renderer.render(elem, {
|
|
237
|
+
noDeferredRendering: this.noDeferredRendering
|
|
238
|
+
});
|
|
236
239
|
}
|
|
237
240
|
}
|
|
238
241
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import '../colors/colors.js';
|
|
2
2
|
import { css, html } from 'lit-element/lit-element.js';
|
|
3
|
+
import { getUniqueId } from '../../helpers/uniqueId.js';
|
|
3
4
|
import { ListItemMixin } from './list-item-mixin.js';
|
|
4
5
|
|
|
5
6
|
export const ListItemButtonMixin = superclass => class extends ListItemMixin(superclass) {
|
|
@@ -34,13 +35,18 @@ export const ListItemButtonMixin = superclass => class extends ListItemMixin(sup
|
|
|
34
35
|
return styles;
|
|
35
36
|
}
|
|
36
37
|
|
|
38
|
+
constructor() {
|
|
39
|
+
super();
|
|
40
|
+
this._primaryActionId = getUniqueId();
|
|
41
|
+
}
|
|
42
|
+
|
|
37
43
|
_onButtonClick() {
|
|
38
44
|
/** Dispatched when the item's primary button action is clicked */
|
|
39
45
|
this.dispatchEvent(new CustomEvent('d2l-list-item-button-click', { bubbles: true }));
|
|
40
46
|
}
|
|
41
47
|
|
|
42
48
|
_renderPrimaryAction(labelledBy) {
|
|
43
|
-
return html`<button aria-labelledby="${labelledBy}" @click="${this._onButtonClick}"></button>`;
|
|
49
|
+
return html`<button id="${this._primaryActionId}" aria-labelledby="${labelledBy}" @click="${this._onButtonClick}"></button>`;
|
|
44
50
|
}
|
|
45
51
|
|
|
46
52
|
};
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import '../button/button-icon.js';
|
|
2
2
|
import '../icons/icon.js';
|
|
3
|
+
import '../tooltip/tooltip.js';
|
|
3
4
|
import { css, html, LitElement } from 'lit-element/lit-element.js';
|
|
4
5
|
import { buttonStyles } from '../button/button-styles.js';
|
|
5
6
|
import { findComposedAncestor } from '../../helpers/dom.js';
|
|
6
7
|
import { getFirstFocusableDescendant } from '../../helpers/focus.js';
|
|
8
|
+
import { getUniqueId } from '../../helpers/uniqueId.js';
|
|
7
9
|
import { LocalizeCoreElement } from '../../lang/localize-core-element.js';
|
|
8
10
|
import { RtlMixin } from '../../mixins/rtl-mixin.js';
|
|
9
11
|
|
|
@@ -36,6 +38,8 @@ export const dragActions = Object.freeze({
|
|
|
36
38
|
up: 'up'
|
|
37
39
|
});
|
|
38
40
|
|
|
41
|
+
let hasDisplayedKeyboardTooltip = false;
|
|
42
|
+
|
|
39
43
|
/**
|
|
40
44
|
* @fires d2l-list-item-drag-handle-action - Dispatched when an action performed on the drag handle
|
|
41
45
|
*/
|
|
@@ -58,6 +62,7 @@ class ListItemDragHandle extends LocalizeCoreElement(RtlMixin(LitElement)) {
|
|
|
58
62
|
* @type {string}
|
|
59
63
|
*/
|
|
60
64
|
text: { type: String },
|
|
65
|
+
_displayKeyboardTooltip: { type: Boolean },
|
|
61
66
|
_keyboardActive: { type: Boolean }
|
|
62
67
|
};
|
|
63
68
|
}
|
|
@@ -109,6 +114,15 @@ class ListItemDragHandle extends LocalizeCoreElement(RtlMixin(LitElement)) {
|
|
|
109
114
|
cursor: default;
|
|
110
115
|
opacity: 0.5;
|
|
111
116
|
}
|
|
117
|
+
d2l-tooltip > div {
|
|
118
|
+
font-weight: 700;
|
|
119
|
+
}
|
|
120
|
+
d2l-tooltip > ul {
|
|
121
|
+
padding-inline-start: 1rem;
|
|
122
|
+
}
|
|
123
|
+
.d2l-list-item-drag-handle-tooltip-key {
|
|
124
|
+
font-weight: 700;
|
|
125
|
+
}
|
|
112
126
|
`];
|
|
113
127
|
}
|
|
114
128
|
|
|
@@ -117,6 +131,8 @@ class ListItemDragHandle extends LocalizeCoreElement(RtlMixin(LitElement)) {
|
|
|
117
131
|
|
|
118
132
|
this.disabled = false;
|
|
119
133
|
|
|
134
|
+
this._buttonId = getUniqueId();
|
|
135
|
+
this._displayKeyboardTooltip = false;
|
|
120
136
|
this._keyboardActive = false;
|
|
121
137
|
this._movingElement = false;
|
|
122
138
|
}
|
|
@@ -219,7 +235,14 @@ class ListItemDragHandle extends LocalizeCoreElement(RtlMixin(LitElement)) {
|
|
|
219
235
|
this._movingElement = false;
|
|
220
236
|
}
|
|
221
237
|
|
|
222
|
-
|
|
238
|
+
_onFocusInKeyboardButton() {
|
|
239
|
+
if (hasDisplayedKeyboardTooltip) return;
|
|
240
|
+
this._displayKeyboardTooltip = true;
|
|
241
|
+
hasDisplayedKeyboardTooltip = true;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
_onFocusOutKeyboardButton(e) {
|
|
245
|
+
this._displayKeyboardTooltip = false;
|
|
223
246
|
if (this._movingElement) {
|
|
224
247
|
this._movingElement = false;
|
|
225
248
|
e.stopPropagation();
|
|
@@ -266,17 +289,32 @@ class ListItemDragHandle extends LocalizeCoreElement(RtlMixin(LitElement)) {
|
|
|
266
289
|
_renderKeyboardDragging() {
|
|
267
290
|
return html`
|
|
268
291
|
<button
|
|
292
|
+
aria-label="${this._defaultLabel}"
|
|
293
|
+
aria-live="assertive"
|
|
269
294
|
class="d2l-list-item-drag-handle-keyboard-button"
|
|
270
|
-
@
|
|
271
|
-
@
|
|
295
|
+
@focusin="${this._onFocusInKeyboardButton}"
|
|
296
|
+
@focusout="${this._onFocusOutKeyboardButton}"
|
|
297
|
+
id="${this._buttonId}"
|
|
272
298
|
@keydown="${this._onPreventDefault}"
|
|
273
|
-
|
|
274
|
-
aria-label="${this._defaultLabel}">
|
|
299
|
+
@keyup="${this._onActiveKeyboard}">
|
|
275
300
|
<d2l-icon icon="tier1:arrow-toggle-up" @click="${this._dispatchActionUp}" class="d2l-button-icon"></d2l-icon>
|
|
276
301
|
<d2l-icon icon="tier1:arrow-toggle-down" @click="${this._dispatchActionDown}" class="d2l-button-icon"></d2l-icon>
|
|
277
302
|
</button>
|
|
303
|
+
${this._displayKeyboardTooltip ? html`<d2l-tooltip align="start" for="${this._buttonId}" for-type="descriptor">${this._renderTooltipContent()}</d2l-tooltip>` : ''}
|
|
278
304
|
`;
|
|
279
305
|
}
|
|
306
|
+
|
|
307
|
+
_renderTooltipContent() {
|
|
308
|
+
return html`
|
|
309
|
+
<div>${this.localize('components.list-item-drag-handle-tooltip.title')}</div>
|
|
310
|
+
<ul>
|
|
311
|
+
<li><span class="d2l-list-item-drag-handle-tooltip-key">${this.localize('components.list-item-drag-handle-tooltip.enter-key')}</span> - ${this.localize('components.list-item-drag-handle-tooltip.enter-desc')}</li>
|
|
312
|
+
<li><span class="d2l-list-item-drag-handle-tooltip-key">${this.localize('components.list-item-drag-handle-tooltip.up-down-key')}</span> - ${this.localize('components.list-item-drag-handle-tooltip.up-down-desc')}</li>
|
|
313
|
+
<li><span class="d2l-list-item-drag-handle-tooltip-key">${this.localize('components.list-item-drag-handle-tooltip.left-right-key')}</span> - ${this.localize('components.list-item-drag-handle-tooltip.left-right-desc')}</li>
|
|
314
|
+
</ul>
|
|
315
|
+
`;
|
|
316
|
+
}
|
|
317
|
+
|
|
280
318
|
}
|
|
281
319
|
|
|
282
320
|
customElements.define('d2l-list-item-drag-handle', ListItemDragHandle);
|
|
@@ -31,6 +31,7 @@ const keyCodes = {
|
|
|
31
31
|
* @slot content - Content of the list item, such as that in a list-item-content component.
|
|
32
32
|
* @slot content-action - Action associated with the content, such as a navigation link
|
|
33
33
|
* @slot actions - Other actions for the list item on the far right, such as a context menu
|
|
34
|
+
* @slot nested - Optional `d2l-list` for creating nested lists
|
|
34
35
|
*/
|
|
35
36
|
class ListItemGenericLayout extends RtlMixin(LitElement) {
|
|
36
37
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import '../colors/colors.js';
|
|
2
2
|
import { css, html } from 'lit-element/lit-element.js';
|
|
3
|
+
import { getUniqueId } from '../../helpers/uniqueId.js';
|
|
3
4
|
import { ListItemMixin } from './list-item-mixin.js';
|
|
4
5
|
|
|
5
6
|
export const ListItemLinkMixin = superclass => class extends ListItemMixin(superclass) {
|
|
@@ -42,6 +43,7 @@ export const ListItemLinkMixin = superclass => class extends ListItemMixin(super
|
|
|
42
43
|
constructor() {
|
|
43
44
|
super();
|
|
44
45
|
this.actionHref = null;
|
|
46
|
+
this._primaryActionId = getUniqueId();
|
|
45
47
|
}
|
|
46
48
|
|
|
47
49
|
_handleLinkClick() {
|
|
@@ -51,7 +53,7 @@ export const ListItemLinkMixin = superclass => class extends ListItemMixin(super
|
|
|
51
53
|
|
|
52
54
|
_renderPrimaryAction(labelledBy) {
|
|
53
55
|
if (!this.actionHref) return;
|
|
54
|
-
return html`<a aria-labelledby="${labelledBy}" href="${this.actionHref}" @click="${this._handleLinkClick}"></a>`;
|
|
56
|
+
return html`<a id="${this._primaryActionId}" aria-labelledby="${labelledBy}" href="${this.actionHref}" @click="${this._handleLinkClick}"></a>`;
|
|
55
57
|
}
|
|
56
58
|
|
|
57
59
|
};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import '../colors/colors.js';
|
|
2
2
|
import './list-item-generic-layout.js';
|
|
3
3
|
import './list-item-placement-marker.js';
|
|
4
|
+
import '../tooltip/tooltip.js';
|
|
4
5
|
import { css, html } from 'lit-element/lit-element.js';
|
|
5
6
|
import { findComposedAncestor, getComposedParent } from '../../helpers/dom.js';
|
|
6
7
|
import { classMap } from 'lit-html/directives/class-map.js';
|
|
@@ -10,10 +11,28 @@ import { ifDefined } from 'lit-html/directives/if-defined.js';
|
|
|
10
11
|
import { ListItemCheckboxMixin } from './list-item-checkbox-mixin.js';
|
|
11
12
|
import { ListItemDragDropMixin } from './list-item-drag-drop-mixin.js';
|
|
12
13
|
import { ListItemRoleMixin } from './list-item-role-mixin.js';
|
|
14
|
+
import { LocalizeCoreElement } from '../../lang/localize-core-element.js';
|
|
13
15
|
import { nothing } from 'lit-html';
|
|
14
16
|
import ResizeObserver from 'resize-observer-polyfill';
|
|
15
17
|
import { RtlMixin } from '../../mixins/rtl-mixin.js';
|
|
16
18
|
|
|
19
|
+
let tabPressed = false;
|
|
20
|
+
let tabListenerAdded = false;
|
|
21
|
+
function addTabListener() {
|
|
22
|
+
if (tabListenerAdded) return;
|
|
23
|
+
tabListenerAdded = true;
|
|
24
|
+
document.addEventListener('keydown', e => {
|
|
25
|
+
if (e.keyCode !== 9) return;
|
|
26
|
+
tabPressed = true;
|
|
27
|
+
});
|
|
28
|
+
document.addEventListener('keyup', e => {
|
|
29
|
+
if (e.keyCode !== 9) return;
|
|
30
|
+
tabPressed = false;
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
let hasDisplayedKeyboardTooltip = false;
|
|
35
|
+
|
|
17
36
|
const ro = new ResizeObserver(entries => {
|
|
18
37
|
entries.forEach(entry => {
|
|
19
38
|
if (!entry || !entry.target || !entry.target.resizedCallback) {
|
|
@@ -25,7 +44,7 @@ const ro = new ResizeObserver(entries => {
|
|
|
25
44
|
|
|
26
45
|
const defaultBreakpoints = [842, 636, 580, 0];
|
|
27
46
|
|
|
28
|
-
export const ListItemMixin = superclass => class extends ListItemDragDropMixin(ListItemCheckboxMixin(ListItemRoleMixin(RtlMixin(superclass)))) {
|
|
47
|
+
export const ListItemMixin = superclass => class extends LocalizeCoreElement(ListItemDragDropMixin(ListItemCheckboxMixin(ListItemRoleMixin(RtlMixin(superclass))))) {
|
|
29
48
|
|
|
30
49
|
static get properties() {
|
|
31
50
|
return {
|
|
@@ -40,6 +59,7 @@ export const ListItemMixin = superclass => class extends ListItemDragDropMixin(L
|
|
|
40
59
|
*/
|
|
41
60
|
slim: { type: Boolean },
|
|
42
61
|
_breakpoint: { type: Number },
|
|
62
|
+
_displayKeyboardTooltip: { type: Boolean },
|
|
43
63
|
_dropdownOpen: { type: Boolean, attribute: '_dropdown-open', reflect: true },
|
|
44
64
|
_hoveringPrimaryAction: { type: Boolean },
|
|
45
65
|
_focusing: { type: Boolean },
|
|
@@ -237,6 +257,15 @@ export const ListItemMixin = superclass => class extends ListItemDragDropMixin(L
|
|
|
237
257
|
:host([draggable][selected]:not([disabled])) d2l-list-item-generic-layout.d2l-focusing + .d2l-list-item-active-border {
|
|
238
258
|
transform: rotate(1deg);
|
|
239
259
|
}
|
|
260
|
+
d2l-tooltip > div {
|
|
261
|
+
font-weight: 700;
|
|
262
|
+
}
|
|
263
|
+
d2l-tooltip > ul {
|
|
264
|
+
padding-inline-start: 1rem;
|
|
265
|
+
}
|
|
266
|
+
.d2l-list-item-tooltip-key {
|
|
267
|
+
font-weight: 700;
|
|
268
|
+
}
|
|
240
269
|
`];
|
|
241
270
|
|
|
242
271
|
super.styles && styles.unshift(super.styles);
|
|
@@ -249,6 +278,7 @@ export const ListItemMixin = superclass => class extends ListItemDragDropMixin(L
|
|
|
249
278
|
this.slim = false;
|
|
250
279
|
this._breakpoint = 0;
|
|
251
280
|
this._contentId = getUniqueId();
|
|
281
|
+
this._displayKeyboardTooltip = false;
|
|
252
282
|
}
|
|
253
283
|
|
|
254
284
|
get breakpoints() {
|
|
@@ -265,6 +295,9 @@ export const ListItemMixin = superclass => class extends ListItemDragDropMixin(L
|
|
|
265
295
|
connectedCallback() {
|
|
266
296
|
super.connectedCallback();
|
|
267
297
|
ro.observe(this);
|
|
298
|
+
if (this.role === 'rowgroup') {
|
|
299
|
+
addTabListener();
|
|
300
|
+
}
|
|
268
301
|
}
|
|
269
302
|
|
|
270
303
|
disconnectedCallback() {
|
|
@@ -351,6 +384,9 @@ export const ListItemMixin = superclass => class extends ListItemDragDropMixin(L
|
|
|
351
384
|
|
|
352
385
|
_onFocusIn() {
|
|
353
386
|
this._focusing = true;
|
|
387
|
+
if (this.role !== 'rowgroup' || !tabPressed || hasDisplayedKeyboardTooltip) return;
|
|
388
|
+
this._displayKeyboardTooltip = true;
|
|
389
|
+
hasDisplayedKeyboardTooltip = true;
|
|
354
390
|
}
|
|
355
391
|
|
|
356
392
|
_onFocusInPrimaryAction() {
|
|
@@ -359,6 +395,7 @@ export const ListItemMixin = superclass => class extends ListItemDragDropMixin(L
|
|
|
359
395
|
|
|
360
396
|
_onFocusOut() {
|
|
361
397
|
this._focusing = false;
|
|
398
|
+
this._displayKeyboardTooltip = false;
|
|
362
399
|
}
|
|
363
400
|
|
|
364
401
|
_onFocusOutPrimaryAction() {
|
|
@@ -398,6 +435,7 @@ export const ListItemMixin = superclass => class extends ListItemDragDropMixin(L
|
|
|
398
435
|
};
|
|
399
436
|
|
|
400
437
|
const primaryAction = this._renderPrimaryAction ? this._renderPrimaryAction(this._contentId) : null;
|
|
438
|
+
const tooltipForId = (primaryAction ? this._primaryActionId : (this.selectable ? this._checkboxId : null));
|
|
401
439
|
|
|
402
440
|
return html`
|
|
403
441
|
${this._renderTopPlacementMarker(html`<d2l-list-item-placement-marker></d2l-list-item-placement-marker>`)}
|
|
@@ -413,11 +451,11 @@ export const ListItemMixin = superclass => class extends ListItemDragDropMixin(L
|
|
|
413
451
|
${this._renderDragHandle(this._renderOutsideControl)}
|
|
414
452
|
${this._renderDragTarget(this._renderOutsideControlAction)}
|
|
415
453
|
${this.selectable ? html`
|
|
416
|
-
<div slot="control">${
|
|
454
|
+
<div slot="control">${this._renderCheckbox()}</div>
|
|
417
455
|
<div slot="control-action"
|
|
418
456
|
@mouseenter="${this._onMouseEnter}"
|
|
419
457
|
@mouseleave="${this._onMouseLeave}">
|
|
420
|
-
${
|
|
458
|
+
${this._renderCheckboxAction('')}
|
|
421
459
|
</div>` : nothing }
|
|
422
460
|
${primaryAction ? html`
|
|
423
461
|
<div slot="content-action"
|
|
@@ -446,6 +484,7 @@ export const ListItemMixin = superclass => class extends ListItemDragDropMixin(L
|
|
|
446
484
|
<div class="d2l-list-item-active-border"></div>
|
|
447
485
|
</div>
|
|
448
486
|
${this._renderBottomPlacementMarker(html`<d2l-list-item-placement-marker></d2l-list-item-placement-marker>`)}
|
|
487
|
+
${this._displayKeyboardTooltip && tooltipForId ? html`<d2l-tooltip align="start" announced for="${tooltipForId}" for-type="descriptor">${this._renderTooltipContent()}</d2l-tooltip>` : ''}
|
|
449
488
|
`;
|
|
450
489
|
|
|
451
490
|
}
|
|
@@ -458,4 +497,16 @@ export const ListItemMixin = superclass => class extends ListItemDragDropMixin(L
|
|
|
458
497
|
return html`<div slot="outside-control-action" @mouseenter="${this._onMouseEnter}" @mouseleave="${this._onMouseLeave}">${dragTarget}</div>`;
|
|
459
498
|
}
|
|
460
499
|
|
|
500
|
+
_renderTooltipContent() {
|
|
501
|
+
return html`
|
|
502
|
+
<div>${this.localize('components.list-item-tooltip.title')}</div>
|
|
503
|
+
<ul>
|
|
504
|
+
<li><span class="d2l-list-item-tooltip-key">${this.localize('components.list-item-tooltip.enter-key')}</span> - ${this.localize('components.list-item-tooltip.enter-desc')}</li>
|
|
505
|
+
<li><span class="d2l-list-item-tooltip-key">${this.localize('components.list-item-tooltip.up-down-key')}</span> - ${this.localize('components.list-item-tooltip.up-down-desc')}</li>
|
|
506
|
+
<li><span class="d2l-list-item-tooltip-key">${this.localize('components.list-item-tooltip.left-right-key')}</span> - ${this.localize('components.list-item-tooltip.left-right-desc')}</li>
|
|
507
|
+
<li><span class="d2l-list-item-tooltip-key">${this.localize('components.list-item-tooltip.page-up-down-key')}</span> - ${this.localize('components.list-item-tooltip.page-up-down-desc')}</li>
|
|
508
|
+
</ul>
|
|
509
|
+
`;
|
|
510
|
+
}
|
|
511
|
+
|
|
461
512
|
};
|
|
@@ -19,8 +19,9 @@ export const ListItemRoleMixin = superclass => class extends superclass {
|
|
|
19
19
|
|
|
20
20
|
const separators = parent.getAttribute('separators');
|
|
21
21
|
|
|
22
|
-
this.role = parent.grid ? 'rowgroup' : 'listitem';
|
|
22
|
+
this.role = parent.hasAttribute('grid') ? 'rowgroup' : 'listitem';
|
|
23
23
|
this._separators = separators || undefined;
|
|
24
24
|
this._extendSeparators = parent.hasAttribute('extend-separators');
|
|
25
25
|
}
|
|
26
|
+
|
|
26
27
|
};
|
|
@@ -6,6 +6,7 @@ import { menuItemStyles } from './menu-item-styles.js';
|
|
|
6
6
|
/**
|
|
7
7
|
* A menu item component used with JS handlers.
|
|
8
8
|
* @slot - Default content placed inside of the component
|
|
9
|
+
* @slot supporting - Allows supporting information to be displayed on the right-most side of the menu item
|
|
9
10
|
*/
|
|
10
11
|
class MenuItem extends MenuItemMixin(LitElement) {
|
|
11
12
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Subscriber Controllers
|
|
2
2
|
|
|
3
|
-
The `SubscriberRegistryController` and the corresponding `*SubscriberController`s can be used to create a subscription system within your app. Components can
|
|
3
|
+
The `SubscriberRegistryController` and the corresponding `*SubscriberController`s can be used to create a subscription system within your app. Components can set up 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
4
|
|
|
5
5
|
## Usage
|
|
6
6
|
|
|
@@ -27,7 +27,7 @@ class CableSubscription extends LitElement {
|
|
|
27
27
|
{ onSubscribe: this._unlockKidsChannels.bind(this) }, {});
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
getSubscriberController(controllerId) {
|
|
31
31
|
if (controllerId === 'sports') {
|
|
32
32
|
return this._sportsSubscribers;
|
|
33
33
|
} else if (controllerId === 'movies') {
|
|
@@ -51,7 +51,7 @@ class CableSubscription extends LitElement {
|
|
|
51
51
|
|
|
52
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
53
|
|
|
54
|
-
The `*subscriberController`s will use a `
|
|
54
|
+
The `*subscriberController`s will use a `getSubscriberController` 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
55
|
|
|
56
56
|
Once this has been set up, components can subscribe to particular registries two different ways:
|
|
57
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.
|
|
@@ -90,7 +90,7 @@ export class EventSubscriberController {
|
|
|
90
90
|
}
|
|
91
91
|
|
|
92
92
|
hostDisconnected() {
|
|
93
|
-
if (this._registry) this._registry.
|
|
93
|
+
if (this._registry) this._registry.getSubscriberController(this._controllerId).unsubscribe(this._host);
|
|
94
94
|
}
|
|
95
95
|
|
|
96
96
|
}
|
|
@@ -114,7 +114,7 @@ export class IdSubscriberController {
|
|
|
114
114
|
if (this._registryObserver) this._registryObserver.disconnect();
|
|
115
115
|
this._timeouts.forEach(timeoutId => clearTimeout(timeoutId));
|
|
116
116
|
this._registries.forEach(registry => {
|
|
117
|
-
registry.
|
|
117
|
+
registry.getSubscriberController(this._controllerId).unsubscribe(this._host);
|
|
118
118
|
});
|
|
119
119
|
}
|
|
120
120
|
|
|
@@ -123,7 +123,7 @@ export class IdSubscriberController {
|
|
|
123
123
|
|
|
124
124
|
if (this._registryObserver) this._registryObserver.disconnect();
|
|
125
125
|
this._registries.forEach(registry => {
|
|
126
|
-
registry.
|
|
126
|
+
registry.getSubscriberController(this._controllerId).unsubscribe(this._host);
|
|
127
127
|
if (this._callbacks.onUnsubscribe) this._callbacks.onUnsubscribe(registry.id);
|
|
128
128
|
});
|
|
129
129
|
this._registries = new Map();
|
|
@@ -168,7 +168,7 @@ export class IdSubscriberController {
|
|
|
168
168
|
if (this._registries.get(registryId) === registryComponent) return;
|
|
169
169
|
|
|
170
170
|
if (registryComponent) {
|
|
171
|
-
registryComponent.
|
|
171
|
+
registryComponent.getSubscriberController(this._controllerId).subscribe(this._host);
|
|
172
172
|
this._registries.set(registryId, registryComponent);
|
|
173
173
|
if (this._callbacks.onSubscribe) this._callbacks.onSubscribe(registryComponent);
|
|
174
174
|
} else {
|