@brightspace-ui/core 1.209.1 → 1.212.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/README.md +15 -10
- package/components/dropdown/dropdown-content-mixin.js +3 -4
- package/components/dropdown/dropdown-menu.js +1 -3
- package/components/dropdown/dropdown-opener-mixin.js +1 -1
- package/components/list/demo/{list-demo-drag-and-drop-usage.js → list-drag-and-drop-position.js} +3 -2
- package/components/list/demo/list-drag-and-drop.html +12 -19
- package/components/list/demo/list-drag-and-drop.js +171 -0
- package/components/list/list-item-checkbox-mixin.js +4 -10
- package/components/list/list-item-drag-drop-mixin.js +205 -47
- package/components/list/list-item-drag-handle.js +18 -7
- package/components/list/list-item-generic-layout.js +12 -1
- package/components/list/list-item-mixin.js +51 -3
- package/components/list/list.js +30 -12
- package/components/menu/menu-item-mixin.js +3 -1
- package/components/menu/menu-item-styles.js +5 -4
- package/components/menu/menu.js +2 -1
- package/controllers/subscriber/README.md +177 -0
- package/controllers/subscriber/subscriberControllers.js +180 -0
- package/custom-elements.json +121 -35
- package/package.json +10 -7
- package/tools/perf-test-helper.js +0 -45
package/README.md
CHANGED
|
@@ -55,6 +55,8 @@ npm install @brightspace-ui/core
|
|
|
55
55
|
* [Tooltip](components/tooltip/): tooltip components
|
|
56
56
|
* [Typography](components/typography/): typography styles and components
|
|
57
57
|
* [Validation](components/validation/): plugin custom validation logic to native and custom form elements
|
|
58
|
+
* Controllers
|
|
59
|
+
* [Subscriber](controllers/subscriber/): for managing a registry of subscribers in a many-to-many relationship
|
|
58
60
|
* Directives
|
|
59
61
|
* [Animate](directives/animate/): animate showing, hiding and removal of elements
|
|
60
62
|
* Helpers
|
|
@@ -119,29 +121,32 @@ Note: The axe tests require `prefers-reduced-motion` emulation to be turned on i
|
|
|
119
121
|
|
|
120
122
|
This repo uses the [@brightspace-ui/visual-diff utility](https://github.com/BrightspaceUI/visual-diff/) to compare current snapshots against a set of golden snapshots stored in source control.
|
|
121
123
|
|
|
122
|
-
The golden snapshots in source control must be updated by
|
|
124
|
+
The golden snapshots in source control must be updated by the [visual-diff GitHub Action](https://github.com/BrightspaceUI/actions/tree/main/visual-diff). If a pull request results in visual differences, a draft pull request with the new goldens will automatically be opened against its branch.
|
|
123
125
|
|
|
124
|
-
|
|
126
|
+
To run the tests locally to help troubleshoot or develop new tests, first install these dependencies:
|
|
125
127
|
|
|
126
128
|
```shell
|
|
127
|
-
|
|
128
|
-
|
|
129
|
+
npm install @brightspace-ui/visual-diff@X mocha@Y puppeteer@Z --no-save
|
|
130
|
+
```
|
|
129
131
|
|
|
130
|
-
|
|
131
|
-
npx mocha './**/*.visual-diff.js' -t 10000 --require esm
|
|
132
|
+
Replace `X`, `Y` and `Z` with [the current versions](https://github.com/BrightspaceUI/actions/tree/main/visual-diff#current-dependency-versions) the action is using.
|
|
132
133
|
|
|
133
|
-
|
|
134
|
-
npx mocha './**/*.visual-diff.js' -t 10000 --require esm -g some-pattern
|
|
134
|
+
Then run the tests:
|
|
135
135
|
|
|
136
|
+
```shell
|
|
137
|
+
# run visual-diff tests
|
|
138
|
+
npx mocha './**/*.visual-diff.js' -t 10000
|
|
139
|
+
# subset of visual-diff tests:
|
|
140
|
+
npx mocha './**/*.visual-diff.js' -t 10000 -g some-pattern
|
|
136
141
|
# update visual-diff goldens
|
|
137
|
-
npx mocha './**/*.visual-diff.js' -t 10000 --
|
|
142
|
+
npx mocha './**/*.visual-diff.js' -t 10000 --golden
|
|
138
143
|
```
|
|
139
144
|
|
|
140
145
|
## Versioning & Releasing
|
|
141
146
|
|
|
142
147
|
> TL;DR: Commits prefixed with `fix:` and `feat:` will trigger patch and minor releases when merged to `main`. Read on for more details...
|
|
143
148
|
|
|
144
|
-
The [semantic-release GitHub Action](https://github.com/BrightspaceUI/actions/tree/
|
|
149
|
+
The [semantic-release GitHub Action](https://github.com/BrightspaceUI/actions/tree/main/semantic-release) is called from the `release.yml` GitHub Action workflow to handle version changes and releasing.
|
|
145
150
|
|
|
146
151
|
### Version Changes
|
|
147
152
|
|
|
@@ -394,7 +394,7 @@ export const DropdownContentMixin = superclass => class extends LocalizeCoreElem
|
|
|
394
394
|
if (this.opened) {
|
|
395
395
|
this.close();
|
|
396
396
|
} else {
|
|
397
|
-
this.open(applyFocus);
|
|
397
|
+
this.open(!this.noAutoFocus && applyFocus);
|
|
398
398
|
}
|
|
399
399
|
}
|
|
400
400
|
|
|
@@ -518,11 +518,10 @@ export const DropdownContentMixin = superclass => class extends LocalizeCoreElem
|
|
|
518
518
|
|
|
519
519
|
await this.__position();
|
|
520
520
|
this._showBackdrop = this._useMobileStyling && this.mobileTray;
|
|
521
|
-
|
|
522
521
|
if (!this.noAutoFocus && this.__applyFocus) {
|
|
523
522
|
const focusable = getFirstFocusableDescendant(this);
|
|
524
523
|
if (focusable) {
|
|
525
|
-
//
|
|
524
|
+
// Removing the rAF call can allow infinite focus looping to happen in content using a focus trap
|
|
526
525
|
requestAnimationFrame(() => focusable.focus());
|
|
527
526
|
} else {
|
|
528
527
|
content.setAttribute('tabindex', '-1');
|
|
@@ -1014,7 +1013,7 @@ export const DropdownContentMixin = superclass => class extends LocalizeCoreElem
|
|
|
1014
1013
|
const content = this.__getContentContainer();
|
|
1015
1014
|
const focusable = getFirstFocusableDescendant(content);
|
|
1016
1015
|
if (focusable) {
|
|
1017
|
-
//
|
|
1016
|
+
// Removing the rAF call can allow infinite focus looping to happen in content using a focus trap
|
|
1018
1017
|
requestAnimationFrame(() => focusable.focus());
|
|
1019
1018
|
} else {
|
|
1020
1019
|
content.setAttribute('tabindex', '-1');
|
|
@@ -262,7 +262,7 @@ export const DropdownOpenerMixin = superclass => class extends superclass {
|
|
|
262
262
|
this._isHovering = false;
|
|
263
263
|
this.openDropdown(false);
|
|
264
264
|
}
|
|
265
|
-
} else this.toggleOpen(
|
|
265
|
+
} else this.toggleOpen(true);
|
|
266
266
|
}
|
|
267
267
|
|
|
268
268
|
/* used by open-on-hover option */
|
package/components/list/demo/{list-demo-drag-and-drop-usage.js → list-drag-and-drop-position.js}
RENAMED
|
@@ -5,7 +5,8 @@ import { html, LitElement } from 'lit-element/lit-element.js';
|
|
|
5
5
|
import { ifDefined } from 'lit-html/directives/if-defined.js';
|
|
6
6
|
import { repeat } from 'lit-html/directives/repeat.js';
|
|
7
7
|
|
|
8
|
-
class
|
|
8
|
+
class ListDemoDragAndDropPosition extends LitElement {
|
|
9
|
+
|
|
9
10
|
static get properties() {
|
|
10
11
|
return {
|
|
11
12
|
list: { type: Array },
|
|
@@ -92,4 +93,4 @@ class ListDemoDragAndDropUsage extends LitElement {
|
|
|
92
93
|
}
|
|
93
94
|
}
|
|
94
95
|
|
|
95
|
-
customElements.define('d2l-list-
|
|
96
|
+
customElements.define('d2l-demo-list-drag-and-drop-position', ListDemoDragAndDropPosition);
|
|
@@ -6,45 +6,38 @@
|
|
|
6
6
|
<link rel="stylesheet" href="../../demo/styles.css" type="text/css">
|
|
7
7
|
<script type="module">
|
|
8
8
|
import '../../demo/demo-page.js';
|
|
9
|
-
import './list-
|
|
9
|
+
import './list-drag-and-drop-position.js';
|
|
10
|
+
import './list-drag-and-drop.js';
|
|
10
11
|
</script>
|
|
11
12
|
</head>
|
|
12
13
|
<body unresolved>
|
|
13
14
|
|
|
14
15
|
<d2l-demo-page page-title="d2l-list (with drag & drop)">
|
|
15
16
|
|
|
16
|
-
<h2>
|
|
17
|
+
<h2>Position Change Event</h2>
|
|
17
18
|
|
|
18
19
|
<d2l-demo-snippet>
|
|
19
20
|
<template>
|
|
20
|
-
<d2l-list-
|
|
21
|
+
<d2l-demo-list-drag-and-drop-position grid selectable hrefs></d2l-demo-list-drag-and-drop-position>
|
|
21
22
|
</template>
|
|
22
23
|
</d2l-demo-snippet>
|
|
23
24
|
|
|
24
|
-
<h2>
|
|
25
|
+
<h2>Move Event</h2>
|
|
25
26
|
|
|
26
27
|
<d2l-demo-snippet>
|
|
27
28
|
<template>
|
|
28
|
-
<d2l-list-
|
|
29
|
+
<d2l-demo-list-drag-and-drop></d2l-demo-list-drag-and-drop>
|
|
29
30
|
</template>
|
|
30
31
|
</d2l-demo-snippet>
|
|
31
32
|
|
|
32
|
-
<h2>Draggable with Grid and Selectable</h2>
|
|
33
33
|
|
|
34
|
-
|
|
35
|
-
<template>
|
|
36
|
-
<d2l-list-demo-drag-and-drop-usage grid selectable></d2l-list-demo-drag-and-drop-usage>
|
|
37
|
-
</template>
|
|
38
|
-
</d2l-demo-snippet>
|
|
39
|
-
|
|
40
|
-
<h2>All the Fixins (grid, draggable, selectable, hrefs)</h2>
|
|
34
|
+
</d2l-demo-page>
|
|
41
35
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
36
|
+
<script>
|
|
37
|
+
document.body.addEventListener('d2l-list-items-move', e => {
|
|
38
|
+
console.log('d2l-list-items-move', e.detail);
|
|
39
|
+
});
|
|
40
|
+
</script>
|
|
47
41
|
|
|
48
|
-
</d2l-demo-page>
|
|
49
42
|
</body>
|
|
50
43
|
</html>
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import '../list-item-content.js';
|
|
2
|
+
import '../list-item.js';
|
|
3
|
+
import '../list.js';
|
|
4
|
+
import { html, LitElement } from 'lit-element/lit-element.js';
|
|
5
|
+
import { ifDefined } from 'lit-html/directives/if-defined.js';
|
|
6
|
+
import { moveLocations } from '../list-item-drag-drop-mixin.js';
|
|
7
|
+
import { repeat } from 'lit-html/directives/repeat.js';
|
|
8
|
+
|
|
9
|
+
class ListDemoDragAndDrop extends LitElement {
|
|
10
|
+
|
|
11
|
+
static get properties() {
|
|
12
|
+
return {
|
|
13
|
+
items: { type: Array }
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
constructor() {
|
|
18
|
+
super();
|
|
19
|
+
this.items = [{
|
|
20
|
+
key: '1',
|
|
21
|
+
primaryText: 'Introductory Earth Sciences',
|
|
22
|
+
supportingText: 'This course explores the geological processes of the Earth\'s interior and surface. These include volcanism, earthquakes, mountain building, glaciation and weathering.',
|
|
23
|
+
imgSrc: 'https://s.brightspace.com/course-images/images/63b162ab-b582-4bf9-8c1d-1dad04714121/tile-high-density-max-size.jpg',
|
|
24
|
+
items: [{
|
|
25
|
+
key: '1-1',
|
|
26
|
+
primaryText: 'Glaciation',
|
|
27
|
+
supportingText: 'Supporting Info',
|
|
28
|
+
imgSrc: '',
|
|
29
|
+
items: []
|
|
30
|
+
}, {
|
|
31
|
+
key: '1-2',
|
|
32
|
+
primaryText: 'Weathering',
|
|
33
|
+
supportingText: 'Supporting Info',
|
|
34
|
+
imgSrc: '',
|
|
35
|
+
items: []
|
|
36
|
+
}, {
|
|
37
|
+
key: '1-3',
|
|
38
|
+
primaryText: 'Volcanism',
|
|
39
|
+
supportingText: 'Supporting Info',
|
|
40
|
+
imgSrc: '',
|
|
41
|
+
items: []
|
|
42
|
+
}]
|
|
43
|
+
}, {
|
|
44
|
+
key: '2',
|
|
45
|
+
primaryText: 'Flow and Transport Through Fractured Rocks',
|
|
46
|
+
supportingText: 'Fractures are ubiquitous in geologic media and important in disciplines such as physical and contaminant hydrogeology, geotechnical engineering, civil and environmental engineering, petroleum engineering among other areas.',
|
|
47
|
+
imgSrc: 'https://s.brightspace.com/course-images/images/e5fd575a-bc14-4a80-89e1-46f349a76178/tile-high-density-max-size.jpg',
|
|
48
|
+
items: [{
|
|
49
|
+
key: '2-1',
|
|
50
|
+
primaryText: 'Contaminant Transport',
|
|
51
|
+
supportingText: 'Supporting Info',
|
|
52
|
+
imgSrc: '',
|
|
53
|
+
items: []
|
|
54
|
+
}, {
|
|
55
|
+
key: '2-2',
|
|
56
|
+
primaryText: 'Modelling Flow in Fractured Media',
|
|
57
|
+
supportingText: 'Supporting Info',
|
|
58
|
+
imgSrc: '',
|
|
59
|
+
items: []
|
|
60
|
+
}]
|
|
61
|
+
}, {
|
|
62
|
+
key: '3',
|
|
63
|
+
primaryText: 'Applied Wetland Science',
|
|
64
|
+
supportingText: 'Advanced concepts on wetland ecosystems in the context of regional and global earth systems processes such as carbon and nitrogen cycling and climate change, applications of wetland paleoecology, use of isotopes and other geochemical tools in wetland science, and wetland engineering in landscape rehabilitation and ecotechnology.',
|
|
65
|
+
imgSrc: 'https://s.brightspace.com/course-images/images/38e839b1-37fa-470c-8830-b189ce4ae134/tile-high-density-max-size.jpg',
|
|
66
|
+
items: [{
|
|
67
|
+
key: '3-1',
|
|
68
|
+
primaryText: 'Carbon & Nitrogen Cycling',
|
|
69
|
+
supportingText: 'Supporting Info',
|
|
70
|
+
imgSrc: '',
|
|
71
|
+
items: []
|
|
72
|
+
}, {
|
|
73
|
+
key: '3-2',
|
|
74
|
+
primaryText: 'Wetland Engineering',
|
|
75
|
+
supportingText: 'Supporting Info',
|
|
76
|
+
imgSrc: '',
|
|
77
|
+
items: []
|
|
78
|
+
}]
|
|
79
|
+
}];
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
render() {
|
|
83
|
+
const renderList = (items, nested) => {
|
|
84
|
+
return html`
|
|
85
|
+
<d2l-list grid slot="${ifDefined(nested ? 'nested' : undefined)}">
|
|
86
|
+
${repeat(items, item => item.key, item => html`
|
|
87
|
+
<d2l-list-item
|
|
88
|
+
action-href="http://www.d2l.com"
|
|
89
|
+
draggable
|
|
90
|
+
drag-handle-text="${item.primaryText}"
|
|
91
|
+
drop-nested
|
|
92
|
+
key="${item.key}"
|
|
93
|
+
label="${item.primaryText}"
|
|
94
|
+
selectable>
|
|
95
|
+
${nested ? null : html`<img slot="illustration" src="${item.imgSrc}">`}
|
|
96
|
+
<d2l-list-item-content>
|
|
97
|
+
<div>${item.primaryText}</div>
|
|
98
|
+
<div slot="supporting-info">${item.supportingText}</div>
|
|
99
|
+
</d2l-list-item-content>
|
|
100
|
+
${item.items.length > 0 ? renderList(item.items, true) : null}
|
|
101
|
+
</d2l-list-item>
|
|
102
|
+
`)}
|
|
103
|
+
</d2l-list>
|
|
104
|
+
`;
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
return html`
|
|
108
|
+
<div @d2l-list-items-move="${this._handleListItemsMove}">
|
|
109
|
+
${renderList(this.items, false)}
|
|
110
|
+
</div>
|
|
111
|
+
`;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
async _handleListItemsMove(e) {
|
|
115
|
+
|
|
116
|
+
const sourceListItems = e.detail.sourceItems;
|
|
117
|
+
const target = e.detail.target;
|
|
118
|
+
|
|
119
|
+
// helper that gets the array containing item data, the item data, and the index within the array
|
|
120
|
+
const getItemInfo = (items, key) => {
|
|
121
|
+
for (let i = 0; i < items.length; i++) {
|
|
122
|
+
if (items[i].key === key) {
|
|
123
|
+
return { owner: items, item: items[i], index: i };
|
|
124
|
+
}
|
|
125
|
+
if (items[i].items && items[i].items.length > 0) {
|
|
126
|
+
const tempItemData = getItemInfo(items[i].items, key);
|
|
127
|
+
if (tempItemData) return tempItemData;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
const dataToMove = [];
|
|
133
|
+
|
|
134
|
+
// remove data elements from original locations
|
|
135
|
+
sourceListItems.forEach(sourceListItem => {
|
|
136
|
+
const info = getItemInfo(this.items, sourceListItem.key);
|
|
137
|
+
info.owner.splice(info.index, 1);
|
|
138
|
+
dataToMove.push(info.item);
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
// append data elements to new location
|
|
142
|
+
const targetInfo = getItemInfo(this.items, target.item.key);
|
|
143
|
+
let targetItems;
|
|
144
|
+
let targetIndex;
|
|
145
|
+
if (target.location === moveLocations.nest) {
|
|
146
|
+
if (!targetInfo.item.items) targetInfo.item.items = [];
|
|
147
|
+
targetItems = targetInfo.item.items;
|
|
148
|
+
targetIndex = targetItems.length;
|
|
149
|
+
} else {
|
|
150
|
+
targetItems = targetInfo.owner;
|
|
151
|
+
if (target.location === moveLocations.above) targetIndex = targetInfo.index;
|
|
152
|
+
else if (target.location === moveLocations.below) targetIndex = targetInfo.index + 1;
|
|
153
|
+
}
|
|
154
|
+
for (let i = dataToMove.length - 1; i >= 0; i--) {
|
|
155
|
+
targetItems.splice(targetIndex, 0, dataToMove[i]);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
await this.requestUpdate();
|
|
159
|
+
|
|
160
|
+
if (e.detail.keyboardActive) {
|
|
161
|
+
requestAnimationFrame(() => {
|
|
162
|
+
const newItem = this.shadowRoot.querySelector('d2l-list').getListItemByKey(sourceListItems[0].key);
|
|
163
|
+
newItem.activateDragHandle();
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
customElements.define('d2l-demo-list-drag-and-drop', ListDemoDragAndDrop);
|
|
@@ -113,16 +113,6 @@ export const ListItemCheckboxMixin = superclass => class extends SkeletonMixin(L
|
|
|
113
113
|
}));
|
|
114
114
|
}
|
|
115
115
|
|
|
116
|
-
_getNestedList() {
|
|
117
|
-
const nestedSlot = this.shadowRoot.querySelector('slot[name="nested"]');
|
|
118
|
-
let nestedNodes = nestedSlot.assignedNodes();
|
|
119
|
-
if (nestedNodes.length === 0) {
|
|
120
|
-
nestedNodes = [...nestedSlot.childNodes];
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
return nestedNodes.find(node => (node.nodeType === Node.ELEMENT_NODE && node.tagName === 'D2L-LIST'));
|
|
124
|
-
}
|
|
125
|
-
|
|
126
116
|
_onCheckboxActionClick(event) {
|
|
127
117
|
event.preventDefault();
|
|
128
118
|
if (this.disabled) return;
|
|
@@ -140,6 +130,10 @@ export const ListItemCheckboxMixin = superclass => class extends SkeletonMixin(L
|
|
|
140
130
|
}
|
|
141
131
|
}
|
|
142
132
|
|
|
133
|
+
_onNestedSlotChange() {
|
|
134
|
+
this._updateNestedSelectionProvider();
|
|
135
|
+
}
|
|
136
|
+
|
|
143
137
|
_onSelectionProviderConnected(e) {
|
|
144
138
|
e.stopPropagation();
|
|
145
139
|
this._updateNestedSelectionProvider();
|