@brightspace-ui/core 3.177.1 → 3.179.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/filter/demo/filter-load-more-demo.js +47 -1
- package/components/filter/demo/filter-overflow-group.html +8 -0
- package/components/filter/filter-overflow-group.js +77 -17
- package/components/filter/filter.js +72 -36
- package/components/link/README.md +2 -0
- package/components/link/demo/link.html +14 -0
- package/components/link/link.js +50 -2
- package/custom-elements.json +38 -1
- package/helpers/interactive.js +1 -1
- package/package.json +1 -1
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import '../filter.js';
|
|
2
2
|
import '../filter-dimension-set.js';
|
|
3
3
|
import '../filter-dimension-set-value.js';
|
|
4
|
+
import '../filter-overflow-group.js';
|
|
4
5
|
import { html, LitElement } from 'lit';
|
|
5
6
|
import { repeat } from 'lit/directives/repeat.js';
|
|
6
7
|
|
|
@@ -32,11 +33,48 @@ const FullData = [
|
|
|
32
33
|
{ key: 'student', selected:false, text: 'Student' }
|
|
33
34
|
],
|
|
34
35
|
initialCount: 2
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
key: 'dep',
|
|
39
|
+
text: 'Department',
|
|
40
|
+
values: [
|
|
41
|
+
{ key: 'english', selected:false, text: 'English' },
|
|
42
|
+
{ key: 'spanish', selected:false, text: 'Spanish' },
|
|
43
|
+
{ key: 'science', selected:false, text: 'Science' }
|
|
44
|
+
],
|
|
45
|
+
initialCount: 2
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
key: 'grad',
|
|
49
|
+
text: 'Grade Level',
|
|
50
|
+
values: [
|
|
51
|
+
{ key: '1', selected:false, text: '1st Grade' },
|
|
52
|
+
{ key: '2', selected:false, text: '2nd Grade' },
|
|
53
|
+
{ key: '3', selected:false, text: '3rd Grade' }
|
|
54
|
+
],
|
|
55
|
+
initialCount: 2
|
|
56
|
+
}
|
|
57
|
+
,
|
|
58
|
+
{
|
|
59
|
+
key: 'city',
|
|
60
|
+
text: 'City',
|
|
61
|
+
values: [
|
|
62
|
+
{ key: '1', selected:false, text: '1st City' },
|
|
63
|
+
{ key: '2', selected:false, text: '2nd City' },
|
|
64
|
+
{ key: '3', selected:false, text: '3rd City' }
|
|
65
|
+
],
|
|
66
|
+
initialCount: 2
|
|
35
67
|
}
|
|
36
68
|
];
|
|
37
69
|
|
|
38
70
|
class FilterLoadMoreDemo extends LitElement {
|
|
39
71
|
|
|
72
|
+
static get properties() {
|
|
73
|
+
return {
|
|
74
|
+
useOverflowGroup: { type: Boolean, attribute: 'use-overflow-group' }
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
|
|
40
78
|
constructor() {
|
|
41
79
|
super();
|
|
42
80
|
const dimensions = [];
|
|
@@ -60,8 +98,16 @@ class FilterLoadMoreDemo extends LitElement {
|
|
|
60
98
|
}
|
|
61
99
|
|
|
62
100
|
render() {
|
|
101
|
+
if (this.useOverflowGroup) return html`<d2l-filter-overflow-group min-to-show="0">
|
|
102
|
+
${repeat(this._dimensions, dimension => dimension.key, dimension => html`<d2l-filter
|
|
103
|
+
@d2l-filter-change="${this._handleFilterChange}"
|
|
104
|
+
@d2l-filter-dimension-load-more=${this._handleLoadMore}
|
|
105
|
+
@d2l-filter-dimension-search=${this._handleSearch}>
|
|
106
|
+
${this._renderDimensionSet(dimension)}
|
|
107
|
+
</d2l-filter>`)}
|
|
108
|
+
</d2l-filter-overflow-group>`;
|
|
63
109
|
return html`
|
|
64
|
-
<d2l-filter
|
|
110
|
+
<d2l-filter
|
|
65
111
|
@d2l-filter-change="${this._handleFilterChange}"
|
|
66
112
|
@d2l-filter-dimension-load-more=${this._handleLoadMore}
|
|
67
113
|
@d2l-filter-dimension-search=${this._handleSearch}>
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
import '../../filter/filter-dimension-set-value.js';
|
|
11
11
|
import '../../filter/filter-overflow-group.js';
|
|
12
12
|
import '../../filter/filter-tags.js';
|
|
13
|
+
import './filter-load-more-demo.js';
|
|
13
14
|
</script>
|
|
14
15
|
<meta name="viewport" content="width=device-width, minimum-scale=1, initial-scale=1.0">
|
|
15
16
|
<meta charset="UTF-8">
|
|
@@ -233,6 +234,13 @@
|
|
|
233
234
|
<d2l-filter-tags filter-ids="filter1 filter2 filter3 filter4 filter5 filter6" label="Applied Filters:"></d2l-filter-tags>
|
|
234
235
|
</template>
|
|
235
236
|
</d2l-demo-snippet>
|
|
237
|
+
|
|
238
|
+
<h2>Filter Overflow Group with Load More and Search</h2>
|
|
239
|
+
<d2l-demo-snippet>
|
|
240
|
+
<template>
|
|
241
|
+
<d2l-filter-load-more-demo use-overflow-group></d2l-filter-load-more-demo>
|
|
242
|
+
</template>
|
|
243
|
+
</d2l-demo-snippet>
|
|
236
244
|
</d2l-demo-page>
|
|
237
245
|
</body>
|
|
238
246
|
</html>
|
|
@@ -4,11 +4,7 @@ import { css, html, LitElement } from 'lit';
|
|
|
4
4
|
import { OVERFLOW_CLASS, OverflowGroupMixin } from '../overflow-group/overflow-group-mixin.js';
|
|
5
5
|
import { getUniqueId } from '../../helpers/uniqueId.js';
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
const dimensionSets = node.querySelectorAll('d2l-filter-dimension-set');
|
|
9
|
-
const clones = Array.from(dimensionSets).map((set) => set.cloneNode(true));
|
|
10
|
-
return clones;
|
|
11
|
-
}
|
|
7
|
+
const updateEvents = ['d2l-filter-dimension-load-more', 'd2l-filter-dimension-search'];
|
|
12
8
|
|
|
13
9
|
/**
|
|
14
10
|
* A component that can be used to display a group of filters that will be put into an overflow filter when they no longer fit on the first line of their container
|
|
@@ -23,6 +19,7 @@ class FilterOverflowGroup extends OverflowGroupMixin(LitElement) {
|
|
|
23
19
|
* @type {boolean}
|
|
24
20
|
*/
|
|
25
21
|
tags: { type: Boolean },
|
|
22
|
+
_openedDimensions: { state: true },
|
|
26
23
|
_filterIds: { state: true }
|
|
27
24
|
};
|
|
28
25
|
}
|
|
@@ -39,10 +36,18 @@ class FilterOverflowGroup extends OverflowGroupMixin(LitElement) {
|
|
|
39
36
|
super();
|
|
40
37
|
|
|
41
38
|
this._filterIds = '';
|
|
39
|
+
this._openedDimensions = [];
|
|
40
|
+
this._updateFilterData = this._updateFilterData.bind(this);
|
|
41
|
+
this._handleSlottedFilterChange = this._handleSlottedFilterChange.bind(this);
|
|
42
|
+
this._handleSlottedDimensionFirstOpen = this._handleSlottedDimensionFirstOpen.bind(this);
|
|
42
43
|
}
|
|
43
44
|
|
|
44
45
|
connectedCallback() {
|
|
45
46
|
super.connectedCallback();
|
|
47
|
+
for (const event of updateEvents)
|
|
48
|
+
this.addEventListener(event, this._updateFilterData);
|
|
49
|
+
this.addEventListener('d2l-filter-change', this._handleSlottedFilterChange);
|
|
50
|
+
this.addEventListener('d2l-filter-dimension-first-open', this._handleSlottedDimensionFirstOpen);
|
|
46
51
|
|
|
47
52
|
if (!this.tags) return;
|
|
48
53
|
|
|
@@ -51,10 +56,12 @@ class FilterOverflowGroup extends OverflowGroupMixin(LitElement) {
|
|
|
51
56
|
this.appendChild(this._filterTags);
|
|
52
57
|
}
|
|
53
58
|
|
|
54
|
-
|
|
55
|
-
super.
|
|
56
|
-
|
|
57
|
-
|
|
59
|
+
disconnectedCallback() {
|
|
60
|
+
super.disconnectedCallback();
|
|
61
|
+
for (const event of updateEvents)
|
|
62
|
+
this.removeEventListener(event, this._updateFilterData);
|
|
63
|
+
this.removeEventListener('d2l-filter-change', this._handleSlottedFilterChange);
|
|
64
|
+
this.removeEventListener('d2l-filter-dimension-first-open', this._handleSlottedDimensionFirstOpen);
|
|
58
65
|
}
|
|
59
66
|
|
|
60
67
|
updated(changedProperties) {
|
|
@@ -79,30 +86,83 @@ class FilterOverflowGroup extends OverflowGroupMixin(LitElement) {
|
|
|
79
86
|
node.setAttribute('data-filter-tags-subscribed', 'data-filter-tags-subscribed');
|
|
80
87
|
}
|
|
81
88
|
|
|
82
|
-
return
|
|
89
|
+
return node._dimensions;
|
|
83
90
|
}
|
|
84
91
|
|
|
85
92
|
getOverflowContainer(overflowItems) {
|
|
93
|
+
const newDimensions = overflowItems.reduce((p, n) => p.concat(n), []).map(dim => {
|
|
94
|
+
return { ...dim, values: dim.values.map(v => ({ ...v })) };
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
/* eslint-disable lit/no-private-properties */
|
|
86
98
|
return html`
|
|
87
|
-
<d2l-filter
|
|
88
|
-
${
|
|
99
|
+
<d2l-filter
|
|
100
|
+
class="${OVERFLOW_CLASS} vdiff-target"
|
|
101
|
+
_ignoreSlotChanges
|
|
102
|
+
._openedDimensions=${this._openedDimensions}
|
|
103
|
+
._dimensions=${newDimensions}
|
|
104
|
+
@d2l-filter-change="${this.#handleFilterChange}"
|
|
105
|
+
@d2l-filter-dimension-load-more="${this.#handleFilterLoadMore}"
|
|
106
|
+
@d2l-filter-dimension-search="${this.#handleFilterSearch}"
|
|
107
|
+
@d2l-filter-dimension-first-open="${this.#handleFirstOpen}">
|
|
89
108
|
</d2l-filter>
|
|
90
109
|
`;
|
|
110
|
+
/* eslint-enable lit/no-private-properties */
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
_handleSlottedDimensionFirstOpen(e) {
|
|
114
|
+
this._openedDimensions.push(e.detail.key);
|
|
115
|
+
this.requestUpdate();
|
|
91
116
|
}
|
|
92
117
|
|
|
93
|
-
|
|
94
|
-
const target = (e.target.classList && e.target.classList.contains(OVERFLOW_CLASS)) ? this : e.target;
|
|
118
|
+
_handleSlottedFilterChange(e) {
|
|
95
119
|
e.detail.dimensions.forEach((dimension) => {
|
|
96
|
-
const filterSet = target.querySelector(`d2l-filter-dimension-set[key=${dimension.dimensionKey}`);
|
|
97
|
-
if (!filterSet) return;
|
|
98
120
|
dimension.changes.forEach((change) => {
|
|
99
|
-
const filterSetValue =
|
|
121
|
+
const filterSetValue = this.querySelector(`d2l-filter-dimension-set[key=${dimension.dimensionKey}] > d2l-filter-dimension-set-value[key="${change.valueKey}"]`);
|
|
100
122
|
if (!filterSetValue) return;
|
|
101
123
|
filterSetValue.selected = change.selected;
|
|
102
124
|
});
|
|
103
125
|
});
|
|
104
126
|
}
|
|
105
127
|
|
|
128
|
+
async _updateFilterData() {
|
|
129
|
+
await Promise.all([...this.querySelectorAll('d2l-filter')].map(f => f.updateComplete));
|
|
130
|
+
this.requestUpdate();
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
#handleFilterChange(e) {
|
|
134
|
+
e.detail.dimensions.forEach((dimension) => {
|
|
135
|
+
this.#runOnFilterDimension(dimension.dimensionKey, filter => {
|
|
136
|
+
filter.requestFilterChangeEvent(e.detail.allCleared, [dimension]);
|
|
137
|
+
});
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
#handleFilterLoadMore(e) {
|
|
142
|
+
this.#runOnFilterDimension(e.detail.key, filter => {
|
|
143
|
+
filter.requestFilterLoadMoreEvent(e.detail.key, e.detail.value, e.detail.loadMoreCompleteCallback);
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
#handleFilterSearch(e) {
|
|
148
|
+
this.#runOnFilterDimension(e.detail.key, filter => {
|
|
149
|
+
filter.requestFilterSearchEvent(e.detail.key, e.detail.value, e.detail.searchCompleteCallback);
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
#handleFirstOpen(e) {
|
|
154
|
+
this.#runOnFilterDimension(e.detail.key, filter => {
|
|
155
|
+
filter.requestFilterDimensionFirstOpenEvent(e.detail.key);
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
#runOnFilterDimension(key, callback) {
|
|
160
|
+
const dimension = this.querySelector(`d2l-filter-dimension-set[key=${key}]`);
|
|
161
|
+
const filter = dimension?.parentNode;
|
|
162
|
+
if (filter?.tagName !== 'D2L-FILTER') return;
|
|
163
|
+
callback(filter);
|
|
164
|
+
}
|
|
165
|
+
|
|
106
166
|
}
|
|
107
167
|
|
|
108
168
|
customElements.define('d2l-filter-overflow-group', FilterOverflowGroup);
|
|
@@ -93,6 +93,7 @@ class Filter extends FocusMixin(LocalizeCoreElement(LitElement)) {
|
|
|
93
93
|
_activeDimensionKey: { type: String, attribute: false },
|
|
94
94
|
_dimensions: { type: Array, attribute: false },
|
|
95
95
|
_displayKeyboardTooltip: { state: true },
|
|
96
|
+
_ignoreSlotChanges: { type: Boolean },
|
|
96
97
|
_minWidth: { type: Number, attribute: false },
|
|
97
98
|
_totalAppliedCount: { type: Number, attribute: false }
|
|
98
99
|
};
|
|
@@ -228,6 +229,7 @@ class Filter extends FocusMixin(LocalizeCoreElement(LitElement)) {
|
|
|
228
229
|
this._changeEventsToDispatch = new Map();
|
|
229
230
|
this._dimensions = [];
|
|
230
231
|
this._displayKeyboardTooltip = false;
|
|
232
|
+
this._ignoreSlotChanges = false;
|
|
231
233
|
this._minWidth = 285;
|
|
232
234
|
this._openedDimensions = [];
|
|
233
235
|
this._totalAppliedCount = 0;
|
|
@@ -332,7 +334,8 @@ class Filter extends FocusMixin(LocalizeCoreElement(LitElement)) {
|
|
|
332
334
|
`;
|
|
333
335
|
}
|
|
334
336
|
|
|
335
|
-
|
|
337
|
+
willUpdate(changedProperties) {
|
|
338
|
+
super.willUpdate(changedProperties);
|
|
336
339
|
if (
|
|
337
340
|
changedProperties.has('opened')
|
|
338
341
|
&& this.opened
|
|
@@ -341,13 +344,70 @@ class Filter extends FocusMixin(LocalizeCoreElement(LitElement)) {
|
|
|
341
344
|
) {
|
|
342
345
|
this._updateDimensionShouldBubble(this._dimensions[0]);
|
|
343
346
|
}
|
|
344
|
-
|
|
347
|
+
if (changedProperties.has('_dimensions')) {
|
|
348
|
+
this._setFilterCounts();
|
|
349
|
+
this._activeFiltersSubscribers.updateSubscribers();
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
requestFilterChangeEvent(allCleared, dimensions) {
|
|
354
|
+
this.dispatchEvent(new CustomEvent('d2l-filter-change', {
|
|
355
|
+
bubbles: true,
|
|
356
|
+
composed: false,
|
|
357
|
+
detail: { allCleared, dimensions }
|
|
358
|
+
}));
|
|
345
359
|
}
|
|
346
360
|
|
|
347
361
|
requestFilterClearAll() {
|
|
348
362
|
this._handleClearAll();
|
|
349
363
|
}
|
|
350
364
|
|
|
365
|
+
requestFilterDimensionFirstOpenEvent(dimensionKey) {
|
|
366
|
+
this._openedDimensions.push(dimensionKey);
|
|
367
|
+
this.dispatchEvent(new CustomEvent('d2l-filter-dimension-first-open', {
|
|
368
|
+
bubbles: true,
|
|
369
|
+
composed: false,
|
|
370
|
+
detail: { key: dimensionKey }
|
|
371
|
+
}));
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
requestFilterLoadMoreEvent(key, searchValue, callback = () => {}) {
|
|
375
|
+
const applySearch = this._getSearchCallback(key);
|
|
376
|
+
this.dispatchEvent(new CustomEvent('d2l-filter-dimension-load-more', {
|
|
377
|
+
detail: {
|
|
378
|
+
key: key,
|
|
379
|
+
value: searchValue,
|
|
380
|
+
loadMoreCompleteCallback: (options) => {
|
|
381
|
+
applySearch(options);
|
|
382
|
+
callback(options);
|
|
383
|
+
}
|
|
384
|
+
},
|
|
385
|
+
bubbles: true,
|
|
386
|
+
composed: false
|
|
387
|
+
}));
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
requestFilterSearchEvent(key, searchValue, callback = () => {}) {
|
|
391
|
+
const dimension = this._getDimensionByKey(key);
|
|
392
|
+
dimension.searchValue = searchValue;
|
|
393
|
+
dimension.loading = true;
|
|
394
|
+
this.requestUpdate();
|
|
395
|
+
const searchCallback = this._getSearchCallback(key);
|
|
396
|
+
|
|
397
|
+
this.dispatchEvent(new CustomEvent('d2l-filter-dimension-search', {
|
|
398
|
+
bubbles: true,
|
|
399
|
+
composed: false,
|
|
400
|
+
detail: {
|
|
401
|
+
key: dimension.key,
|
|
402
|
+
value: dimension.searchValue,
|
|
403
|
+
searchCompleteCallback: (options) => {
|
|
404
|
+
searchCallback(options);
|
|
405
|
+
callback(options);
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
}));
|
|
409
|
+
}
|
|
410
|
+
|
|
351
411
|
requestFilterValueClear(keyObject) {
|
|
352
412
|
const dimension = this._getDimensionByKey(keyObject.dimension);
|
|
353
413
|
|
|
@@ -660,11 +720,7 @@ class Filter extends FocusMixin(LocalizeCoreElement(LitElement)) {
|
|
|
660
720
|
dimension.changes = Array.from(dimension.changes.values());
|
|
661
721
|
});
|
|
662
722
|
|
|
663
|
-
this.
|
|
664
|
-
bubbles: true,
|
|
665
|
-
composed: false,
|
|
666
|
-
detail: { allCleared: allCleared, dimensions: dimensions }
|
|
667
|
-
}));
|
|
723
|
+
this.requestFilterChangeEvent(allCleared, dimensions);
|
|
668
724
|
this._changeEventsToDispatch = new Map();
|
|
669
725
|
clearTimeout(this._changeEventTimeout);
|
|
670
726
|
this._activeFiltersSubscribers.updateSubscribers();
|
|
@@ -678,11 +734,10 @@ class Filter extends FocusMixin(LocalizeCoreElement(LitElement)) {
|
|
|
678
734
|
|
|
679
735
|
_dispatchDimensionFirstOpenEvent(dimension) {
|
|
680
736
|
if (!this._openedDimensions.includes(dimension.key)) {
|
|
681
|
-
this.
|
|
737
|
+
this.requestFilterDimensionFirstOpenEvent(dimension.key);
|
|
682
738
|
if (dimension.searchType === 'manual') {
|
|
683
739
|
this._search(dimension);
|
|
684
740
|
}
|
|
685
|
-
this._openedDimensions.push(dimension.key);
|
|
686
741
|
}
|
|
687
742
|
}
|
|
688
743
|
|
|
@@ -694,9 +749,10 @@ class Filter extends FocusMixin(LocalizeCoreElement(LitElement)) {
|
|
|
694
749
|
return this._dimensions.find(dimension => dimension.key === key);
|
|
695
750
|
}
|
|
696
751
|
|
|
697
|
-
_getSearchCallback(
|
|
752
|
+
_getSearchCallback(key) {
|
|
698
753
|
return function({ keysToDisplay = [], displayAllKeys = false } = {}) {
|
|
699
754
|
requestAnimationFrame(() => {
|
|
755
|
+
const dimension = this._getDimensionByKey(key);
|
|
700
756
|
dimension.displayAllKeys = displayAllKeys;
|
|
701
757
|
dimension.searchKeysToDisplay = keysToDisplay;
|
|
702
758
|
this._performDimensionSearch(dimension);
|
|
@@ -830,21 +886,11 @@ class Filter extends FocusMixin(LocalizeCoreElement(LitElement)) {
|
|
|
830
886
|
_handleDimensionLoadMore(e) {
|
|
831
887
|
const dimensionKey = e.target.parentNode.id.slice(SET_DIMENSION_ID_PREFIX.length);
|
|
832
888
|
const dimension = this._getDimensionByKey(dimensionKey);
|
|
833
|
-
const applySearch = this._getSearchCallback(dimension);
|
|
834
889
|
|
|
835
|
-
this.
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
loadMoreCompleteCallback: (options) => {
|
|
840
|
-
applySearch(options);
|
|
841
|
-
const menu = this.shadowRoot.querySelector('d2l-dropdown-menu');
|
|
842
|
-
menu ? menu.addEventListener('d2l-dropdown-position', e.detail.complete, { once: true }) : e.detail.complete();
|
|
843
|
-
}
|
|
844
|
-
},
|
|
845
|
-
bubbles: true,
|
|
846
|
-
composed: false
|
|
847
|
-
}));
|
|
890
|
+
this.requestFilterLoadMoreEvent(dimensionKey, dimension.value, () => {
|
|
891
|
+
const menu = this.shadowRoot.querySelector('d2l-dropdown-menu');
|
|
892
|
+
menu ? menu.addEventListener('d2l-dropdown-position', e.detail.complete, { once: true }) : e.detail.complete();
|
|
893
|
+
});
|
|
848
894
|
}
|
|
849
895
|
|
|
850
896
|
_handleDimensionShowComplete() {
|
|
@@ -919,6 +965,7 @@ class Filter extends FocusMixin(LocalizeCoreElement(LitElement)) {
|
|
|
919
965
|
|
|
920
966
|
_handleSlotChange(e) {
|
|
921
967
|
const dimensionNodes = this._getSlottedNodes(e.target);
|
|
968
|
+
if (this._ignoreSlotChanges) return;
|
|
922
969
|
|
|
923
970
|
this._dimensions = dimensionNodes.map(dimension => {
|
|
924
971
|
const type = dimension.tagName.toLowerCase();
|
|
@@ -951,9 +998,6 @@ class Filter extends FocusMixin(LocalizeCoreElement(LitElement)) {
|
|
|
951
998
|
|
|
952
999
|
return info;
|
|
953
1000
|
});
|
|
954
|
-
|
|
955
|
-
this._setFilterCounts();
|
|
956
|
-
this._activeFiltersSubscribers.updateSubscribers();
|
|
957
1001
|
}
|
|
958
1002
|
|
|
959
1003
|
_handleTooltipHide() {
|
|
@@ -1055,15 +1099,7 @@ class Filter extends FocusMixin(LocalizeCoreElement(LitElement)) {
|
|
|
1055
1099
|
dimension.loading = true;
|
|
1056
1100
|
this.requestUpdate();
|
|
1057
1101
|
|
|
1058
|
-
this.
|
|
1059
|
-
bubbles: false,
|
|
1060
|
-
composed: false,
|
|
1061
|
-
detail: {
|
|
1062
|
-
key: dimension.key,
|
|
1063
|
-
value: dimension.searchValue,
|
|
1064
|
-
searchCompleteCallback: this._getSearchCallback(dimension)
|
|
1065
|
-
}
|
|
1066
|
-
}));
|
|
1102
|
+
this.requestFilterSearchEvent(dimension.key, dimension.searchValue);
|
|
1067
1103
|
}
|
|
1068
1104
|
}
|
|
1069
1105
|
|
|
@@ -49,6 +49,8 @@ Import and use the `<d2l-link>` web component instead of the native `<a>` elemen
|
|
|
49
49
|
|--|--|--|
|
|
50
50
|
| `aria-label` | String | Label to provide more context for screen reader users when the link text is not enough |
|
|
51
51
|
| `href` | String, required | URL or URL fragment of the link |
|
|
52
|
+
| `disabled` | Boolean | Disables the link |
|
|
53
|
+
| `disabled-tooltip` | String | Tooltip text when disabled |
|
|
52
54
|
| `download` | String | If the attribute is provided, it will prompt the user to download the resource instead of navigating to it. Additionally, if the attribute is provided with a value, that value will be used for the filename. |
|
|
53
55
|
| `main` | Boolean | Whether to apply the "main" link style |
|
|
54
56
|
| `lines` | Number | The number of lines to display before truncating text with an ellipsis. The text will not be truncated unless a value is specified. |
|
|
@@ -92,6 +92,20 @@
|
|
|
92
92
|
</template>
|
|
93
93
|
</d2l-demo-snippet>
|
|
94
94
|
|
|
95
|
+
<h2>Disabled</h2>
|
|
96
|
+
<d2l-demo-snippet>
|
|
97
|
+
<template>
|
|
98
|
+
<d2l-link disabled href="https://www.d2l.com" target="_blank">Disabled Link</d2l-link>
|
|
99
|
+
</template>
|
|
100
|
+
</d2l-demo-snippet>
|
|
101
|
+
|
|
102
|
+
<h2>Disabled with Tooltip</h2>
|
|
103
|
+
<d2l-demo-snippet>
|
|
104
|
+
<template>
|
|
105
|
+
<d2l-link disabled disabled-tooltip="This link is disabled because you do not have permission" href="https://www.d2l.com" target="_blank">Disabled Link with Tooltip</d2l-link>
|
|
106
|
+
</template>
|
|
107
|
+
</d2l-demo-snippet>
|
|
108
|
+
|
|
95
109
|
</d2l-demo-page>
|
|
96
110
|
</body>
|
|
97
111
|
</html>
|
package/components/link/link.js
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import '../colors/colors.js';
|
|
2
2
|
import '../icons/icon.js';
|
|
3
|
+
import '../tooltip/tooltip.js';
|
|
3
4
|
import { css, html, LitElement, nothing } from 'lit';
|
|
4
5
|
import { getOverflowDeclarations, overflowEllipsisDeclarations } from '../../helpers/overflow.js';
|
|
5
6
|
import { _generateLinkStyles } from './link-styles.js';
|
|
6
7
|
import { classMap } from 'lit/directives/class-map.js';
|
|
7
8
|
import { FocusMixin } from '../../mixins/focus/focus-mixin.js';
|
|
8
9
|
import { getFlag } from '../../helpers/flags.js';
|
|
10
|
+
import { getUniqueId } from '../../helpers/uniqueId.js';
|
|
9
11
|
import { ifDefined } from 'lit/directives/if-defined.js';
|
|
10
12
|
import { LocalizeCoreElement } from '../../helpers/localize-core-element.js';
|
|
11
13
|
import { offscreenStyles } from '../offscreen/offscreen.js';
|
|
@@ -28,6 +30,16 @@ class Link extends LocalizeCoreElement(FocusMixin(LitElement)) {
|
|
|
28
30
|
* @type {string}
|
|
29
31
|
*/
|
|
30
32
|
ariaLabel: { type: String, attribute: 'aria-label' },
|
|
33
|
+
/**
|
|
34
|
+
* Disables the link
|
|
35
|
+
* @type {boolean}
|
|
36
|
+
*/
|
|
37
|
+
disabled: { type: Boolean, reflect: true },
|
|
38
|
+
/**
|
|
39
|
+
* Tooltip text when disabled
|
|
40
|
+
* @type {string}
|
|
41
|
+
*/
|
|
42
|
+
disabledTooltip: { type: String, attribute: 'disabled-tooltip', reflect: true },
|
|
31
43
|
/**
|
|
32
44
|
* Download a URL instead of navigating to it
|
|
33
45
|
* @type {boolean}
|
|
@@ -113,6 +125,24 @@ class Link extends LocalizeCoreElement(FocusMixin(LitElement)) {
|
|
|
113
125
|
--d2l-icon-fill-color: var(--d2l-color-celestine-minus-1);
|
|
114
126
|
}
|
|
115
127
|
|
|
128
|
+
:host([disabled]:not([disabled-tooltip])) a:hover {
|
|
129
|
+
color: var(--d2l-color-celestine);
|
|
130
|
+
text-decoration: none;
|
|
131
|
+
}
|
|
132
|
+
:host([disabled]:not([disabled-tooltip])) a:hover d2l-icon {
|
|
133
|
+
--d2l-icon-fill-color: var(--d2l-color-celestine);
|
|
134
|
+
}
|
|
135
|
+
a[aria-disabled="true"],
|
|
136
|
+
a[aria-disabled="true"]:active {
|
|
137
|
+
cursor: default;
|
|
138
|
+
}
|
|
139
|
+
a[aria-disabled="true"] .d2l-link-content {
|
|
140
|
+
opacity: 0.74;
|
|
141
|
+
}
|
|
142
|
+
a[aria-disabled="true"] d2l-icon {
|
|
143
|
+
opacity: 0.64;
|
|
144
|
+
}
|
|
145
|
+
|
|
116
146
|
@media print {
|
|
117
147
|
d2l-icon {
|
|
118
148
|
display: none;
|
|
@@ -124,6 +154,7 @@ class Link extends LocalizeCoreElement(FocusMixin(LitElement)) {
|
|
|
124
154
|
|
|
125
155
|
constructor() {
|
|
126
156
|
super();
|
|
157
|
+
this.disabled = false;
|
|
127
158
|
this.download = false;
|
|
128
159
|
this.main = false;
|
|
129
160
|
this.small = false;
|
|
@@ -141,6 +172,7 @@ class Link extends LocalizeCoreElement(FocusMixin(LitElement)) {
|
|
|
141
172
|
'd2l-link-small': this.small
|
|
142
173
|
};
|
|
143
174
|
const spanClasses = {
|
|
175
|
+
'd2l-link-content': true,
|
|
144
176
|
'truncate': this.lines > 1,
|
|
145
177
|
'truncate-one': this.lines === 1
|
|
146
178
|
};
|
|
@@ -148,6 +180,9 @@ class Link extends LocalizeCoreElement(FocusMixin(LitElement)) {
|
|
|
148
180
|
const newWindowElements = (this.target === '_blank')
|
|
149
181
|
? html`<span id="new-window"><span style="font-size: 0;"> </span><d2l-icon icon="tier1:new-window"></d2l-icon></span><span class="d2l-offscreen">${this.localize('components.link.open-in-new-window')}</span>`
|
|
150
182
|
: nothing;
|
|
183
|
+
const disabledTooltip = this.disabled && this.disabledTooltip
|
|
184
|
+
? html`<d2l-tooltip class="vdiff-target" for="${this.#linkId}">${this.disabledTooltip}</d2l-tooltip>`
|
|
185
|
+
: nothing;
|
|
151
186
|
|
|
152
187
|
/*
|
|
153
188
|
* NOTICE:
|
|
@@ -155,14 +190,27 @@ class Link extends LocalizeCoreElement(FocusMixin(LitElement)) {
|
|
|
155
190
|
* Do not modify for readability!
|
|
156
191
|
*/
|
|
157
192
|
return html`<a
|
|
193
|
+
aria-disabled="${ifDefined(this.disabled ? 'true' : undefined)}"
|
|
158
194
|
aria-label="${ifDefined(this.ariaLabel)}"
|
|
159
195
|
class="${classMap(linkClasses)}"
|
|
196
|
+
@click="${this.#handleClick}"
|
|
160
197
|
?download="${this.download}"
|
|
161
|
-
href="${ifDefined(this.href)}"
|
|
198
|
+
href="${ifDefined(!this.disabled ? this.href : undefined)}"
|
|
199
|
+
id="${this.#linkId}"
|
|
200
|
+
tabindex="${ifDefined(this.disabled && this.disabledTooltip ? 0 : undefined)}"
|
|
162
201
|
target="${ifDefined(this.target)}"
|
|
163
202
|
><span
|
|
164
203
|
class="${classMap(spanClasses)}"
|
|
165
|
-
style="${styleMap(styles)}"><slot></slot></span>${newWindowElements}</a
|
|
204
|
+
style="${styleMap(styles)}"><slot></slot></span>${newWindowElements}</a>${disabledTooltip}`;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
#linkId = getUniqueId();
|
|
208
|
+
|
|
209
|
+
#handleClick(e) {
|
|
210
|
+
if (this.disabled) {
|
|
211
|
+
e.stopPropagation();
|
|
212
|
+
e.preventDefault();
|
|
213
|
+
}
|
|
166
214
|
}
|
|
167
215
|
|
|
168
216
|
}
|
package/custom-elements.json
CHANGED
|
@@ -4172,7 +4172,20 @@
|
|
|
4172
4172
|
},
|
|
4173
4173
|
{
|
|
4174
4174
|
"name": "d2l-filter-load-more-demo",
|
|
4175
|
-
"path": "./components/filter/demo/filter-load-more-demo.js"
|
|
4175
|
+
"path": "./components/filter/demo/filter-load-more-demo.js",
|
|
4176
|
+
"attributes": [
|
|
4177
|
+
{
|
|
4178
|
+
"name": "use-overflow-group",
|
|
4179
|
+
"type": "boolean"
|
|
4180
|
+
}
|
|
4181
|
+
],
|
|
4182
|
+
"properties": [
|
|
4183
|
+
{
|
|
4184
|
+
"name": "useOverflowGroup",
|
|
4185
|
+
"attribute": "use-overflow-group",
|
|
4186
|
+
"type": "boolean"
|
|
4187
|
+
}
|
|
4188
|
+
]
|
|
4176
4189
|
},
|
|
4177
4190
|
{
|
|
4178
4191
|
"name": "d2l-filter-search-demo",
|
|
@@ -8470,6 +8483,11 @@
|
|
|
8470
8483
|
"description": "ACCESSIBILITY: Label to provide more context for screen reader users when the link text is not enough",
|
|
8471
8484
|
"type": "string"
|
|
8472
8485
|
},
|
|
8486
|
+
{
|
|
8487
|
+
"name": "disabled-tooltip",
|
|
8488
|
+
"description": "Tooltip text when disabled",
|
|
8489
|
+
"type": "string"
|
|
8490
|
+
},
|
|
8473
8491
|
{
|
|
8474
8492
|
"name": "href",
|
|
8475
8493
|
"description": "REQUIRED: URL or URL fragment of the link",
|
|
@@ -8480,6 +8498,12 @@
|
|
|
8480
8498
|
"description": "Where to display the linked URL",
|
|
8481
8499
|
"type": "string"
|
|
8482
8500
|
},
|
|
8501
|
+
{
|
|
8502
|
+
"name": "disabled",
|
|
8503
|
+
"description": "Disables the link",
|
|
8504
|
+
"type": "boolean",
|
|
8505
|
+
"default": "false"
|
|
8506
|
+
},
|
|
8483
8507
|
{
|
|
8484
8508
|
"name": "download",
|
|
8485
8509
|
"description": "Download a URL instead of navigating to it",
|
|
@@ -8512,6 +8536,12 @@
|
|
|
8512
8536
|
"description": "ACCESSIBILITY: Label to provide more context for screen reader users when the link text is not enough",
|
|
8513
8537
|
"type": "string"
|
|
8514
8538
|
},
|
|
8539
|
+
{
|
|
8540
|
+
"name": "disabledTooltip",
|
|
8541
|
+
"attribute": "disabled-tooltip",
|
|
8542
|
+
"description": "Tooltip text when disabled",
|
|
8543
|
+
"type": "string"
|
|
8544
|
+
},
|
|
8515
8545
|
{
|
|
8516
8546
|
"name": "href",
|
|
8517
8547
|
"attribute": "href",
|
|
@@ -8524,6 +8554,13 @@
|
|
|
8524
8554
|
"description": "Where to display the linked URL",
|
|
8525
8555
|
"type": "string"
|
|
8526
8556
|
},
|
|
8557
|
+
{
|
|
8558
|
+
"name": "disabled",
|
|
8559
|
+
"attribute": "disabled",
|
|
8560
|
+
"description": "Disables the link",
|
|
8561
|
+
"type": "boolean",
|
|
8562
|
+
"default": "false"
|
|
8563
|
+
},
|
|
8527
8564
|
{
|
|
8528
8565
|
"name": "download",
|
|
8529
8566
|
"attribute": "download",
|
package/helpers/interactive.js
CHANGED
|
@@ -35,7 +35,7 @@ export function isInteractive(ele, elems, roles) {
|
|
|
35
35
|
return true;
|
|
36
36
|
}
|
|
37
37
|
const role = (ele.getAttribute('role') || '');
|
|
38
|
-
return (nodeName === 'a' && ele.hasAttribute('href')) || roles[role] || false;
|
|
38
|
+
return (nodeName === 'a' && (ele.hasAttribute('href') || ele.getAttribute('tabindex') === '0')) || roles[role] || false;
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
export function isInteractiveInComposedPath(composedPath, predicate, options) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@brightspace-ui/core",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.179.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",
|