@brightspace-ui/core 3.109.0 → 3.110.1
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/inputs/demo/input-checkbox.html +9 -4
- package/components/inputs/docs/input-checkbox.md +43 -9
- package/components/inputs/input-checkbox-group.js +30 -0
- package/components/list/list-item-generic-layout.js +12 -12
- package/components/list/list-item-mixin.js +4 -4
- package/components/list/list-item-role-mixin.js +1 -1
- package/components/list/list.js +2 -2
- package/custom-elements.json +11 -0
- package/package.json +1 -1
@@ -7,6 +7,7 @@
|
|
7
7
|
<script type="module">
|
8
8
|
import '../../demo/demo-page.js';
|
9
9
|
import '../input-checkbox.js';
|
10
|
+
import '../input-checkbox-group.js';
|
10
11
|
</script>
|
11
12
|
</head>
|
12
13
|
<body unresolved>
|
@@ -15,16 +16,20 @@
|
|
15
16
|
<h2>Simple checkbox with label</h2>
|
16
17
|
<d2l-demo-snippet>
|
17
18
|
<template>
|
18
|
-
<d2l-input-checkbox
|
19
|
-
|
19
|
+
<d2l-input-checkbox-group>
|
20
|
+
<d2l-input-checkbox label="Checked item" checked></d2l-input-checkbox>
|
21
|
+
<d2l-input-checkbox label="Unchecked item"></d2l-input-checkbox>
|
22
|
+
</d2l-input-checkbox-group>
|
20
23
|
</template>
|
21
24
|
</d2l-demo-snippet>
|
22
25
|
|
23
26
|
<h2>Checkbox with multi-line label</h2>
|
24
27
|
<d2l-demo-snippet>
|
25
28
|
<template>
|
26
|
-
<d2l-input-checkbox
|
27
|
-
|
29
|
+
<d2l-input-checkbox-group>
|
30
|
+
<d2l-input-checkbox style="overflow: hidden; width: 200px;" label="Label for checkbox that wraps nicely onto multiple lines and stays aligned"></d2l-input-checkbox>
|
31
|
+
<d2l-input-checkbox style="overflow: hidden; width: 200px;" label="https://en.wikipedia.org/wiki/Dark_matter"></d2l-input-checkbox>
|
32
|
+
</d2l-input-checkbox-group>
|
28
33
|
</template>
|
29
34
|
</d2l-demo-snippet>
|
30
35
|
|
@@ -36,16 +36,15 @@ The `<d2l-input-checkbox>` element can be used to get a checkbox and optional vi
|
|
36
36
|
<script type="module">
|
37
37
|
import '@brightspace-ui/core/components/inputs/input-checkbox.js';
|
38
38
|
|
39
|
-
window.addEventListener('load',
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
39
|
+
window.addEventListener('load', () => {
|
40
|
+
document.querySelector('d2l-input-checkbox')
|
41
|
+
.addEventListener('change', e => {
|
42
|
+
console.log('checked value: ', e.target.checked);
|
43
|
+
});
|
44
44
|
});
|
45
45
|
</script>
|
46
46
|
<div>
|
47
|
-
<d2l-input-checkbox
|
48
|
-
<d2l-input-checkbox label="Label for second checkbox"></d2l-input-checkbox>
|
47
|
+
<d2l-input-checkbox label="Label for checkbox"></d2l-input-checkbox>
|
49
48
|
</div>
|
50
49
|
```
|
51
50
|
|
@@ -69,8 +68,8 @@ The `<d2l-input-checkbox>` element can be used to get a checkbox and optional vi
|
|
69
68
|
When the checkbox's state changes, it dispatches the `change` event:
|
70
69
|
|
71
70
|
```javascript
|
72
|
-
checkbox.addEventListener('change',
|
73
|
-
console.log(
|
71
|
+
checkbox.addEventListener('change', e => {
|
72
|
+
console.log(e.target.checked);
|
74
73
|
});
|
75
74
|
```
|
76
75
|
|
@@ -80,6 +79,41 @@ checkbox.addEventListener('change', (e) => {
|
|
80
79
|
* `supporting`: Supporting information which will appear below and be aligned with the checkbox.
|
81
80
|
<!-- docs: end hidden content -->
|
82
81
|
|
82
|
+
### Groups of Checkboxes
|
83
|
+
|
84
|
+
If multiple checkboxes are displayed together, wrapping them in a `<d2l-input-checkbox-group>` provides consistent spacing between each checkbox.
|
85
|
+
|
86
|
+
<!-- docs: demo code -->
|
87
|
+
```html
|
88
|
+
<script type="module">
|
89
|
+
import '@brightspace-ui/core/components/inputs/input-checkbox.js';
|
90
|
+
import '@brightspace-ui/core/components/inputs/input-checkbox-group.js';
|
91
|
+
</script>
|
92
|
+
<d2l-input-checkbox-group>
|
93
|
+
<d2l-input-checkbox label="Option 1"></d2l-input-checkbox>
|
94
|
+
<d2l-input-checkbox label="Option 2"></d2l-input-checkbox>
|
95
|
+
<d2l-input-checkbox label="Option 3"></d2l-input-checkbox>
|
96
|
+
</d2l-input-checkbox-group>
|
97
|
+
```
|
98
|
+
|
99
|
+
Often, the checkboxes in the group are related to each other and may have a label for the whole group. In this case, a `<d2l-input-fieldset>` should be used.
|
100
|
+
|
101
|
+
<!-- docs: demo code -->
|
102
|
+
```html
|
103
|
+
<script type="module">
|
104
|
+
import '@brightspace-ui/core/components/inputs/input-checkbox.js';
|
105
|
+
import '@brightspace-ui/core/components/inputs/input-checkbox-group.js';
|
106
|
+
import '@brightspace-ui/core/components/inputs/input-fieldset.js';
|
107
|
+
</script>
|
108
|
+
<d2l-input-fieldset label="Toppings">
|
109
|
+
<d2l-input-checkbox-group>
|
110
|
+
<d2l-input-checkbox label="Ketchup"></d2l-input-checkbox>
|
111
|
+
<d2l-input-checkbox label="Mustard"></d2l-input-checkbox>
|
112
|
+
<d2l-input-checkbox label="Relish"></d2l-input-checkbox>
|
113
|
+
</d2l-input-checkbox-group>
|
114
|
+
</d2l-input-fieldset>
|
115
|
+
```
|
116
|
+
|
83
117
|
## Applying styles to native checkboxes
|
84
118
|
|
85
119
|
As an alternative to using the `<d2l-input-checkbox>` custom element, you can style a native checkbox inside your own element. Import `input-checkbox-styles.js` and apply the `d2l-input-checkbox` CSS class to the input:
|
@@ -0,0 +1,30 @@
|
|
1
|
+
import { css, html, LitElement } from 'lit';
|
2
|
+
|
3
|
+
/**
|
4
|
+
* A wrapper for <d2l-input-checkbox> components which provides spacing between the items.
|
5
|
+
* @slot - Checkbox components
|
6
|
+
*/
|
7
|
+
class InputCheckboxGroup extends LitElement {
|
8
|
+
|
9
|
+
static get styles() {
|
10
|
+
return css`
|
11
|
+
:host {
|
12
|
+
display: flex;
|
13
|
+
flex-direction: column;
|
14
|
+
gap: 0.6rem;
|
15
|
+
}
|
16
|
+
:host([hidden]) {
|
17
|
+
display: none;
|
18
|
+
}
|
19
|
+
::slotted(d2l-input-checkbox) {
|
20
|
+
margin-bottom: 0;
|
21
|
+
}
|
22
|
+
`;
|
23
|
+
}
|
24
|
+
|
25
|
+
render() {
|
26
|
+
return html`<slot></slot>`;
|
27
|
+
}
|
28
|
+
|
29
|
+
}
|
30
|
+
customElements.define('d2l-input-checkbox-group', InputCheckboxGroup);
|
@@ -214,7 +214,7 @@ class ListItemGenericLayout extends RtlMixin(LitElement) {
|
|
214
214
|
|
215
215
|
connectedCallback() {
|
216
216
|
super.connectedCallback();
|
217
|
-
this.role = this.gridActive ? '
|
217
|
+
this.role = this.gridActive ? 'gridcell' : undefined;
|
218
218
|
}
|
219
219
|
|
220
220
|
firstUpdated() {
|
@@ -265,7 +265,7 @@ class ListItemGenericLayout extends RtlMixin(LitElement) {
|
|
265
265
|
|
266
266
|
_focusFirstRow() {
|
267
267
|
const list = findComposedAncestor(this, (node) => node.tagName === 'D2L-LIST');
|
268
|
-
const row = list.firstElementChild.shadowRoot.querySelector('[role="
|
268
|
+
const row = list.firstElementChild.shadowRoot.querySelector('[role="gridcell"]');
|
269
269
|
if (this.dir === 'rtl') {
|
270
270
|
row._focusLastCell();
|
271
271
|
} else {
|
@@ -288,7 +288,7 @@ class ListItemGenericLayout extends RtlMixin(LitElement) {
|
|
288
288
|
|
289
289
|
_focusLastRow() {
|
290
290
|
const list = findComposedAncestor(this, (node) => node.tagName === 'D2L-LIST');
|
291
|
-
const row = list.lastElementChild.shadowRoot.querySelector('[role="
|
291
|
+
const row = list.lastElementChild.shadowRoot.querySelector('[role="gridcell"]');
|
292
292
|
if (this.dir === 'rtl') {
|
293
293
|
row._focusFirstCell();
|
294
294
|
} else {
|
@@ -320,7 +320,7 @@ class ListItemGenericLayout extends RtlMixin(LitElement) {
|
|
320
320
|
|
321
321
|
_focusNextRow(focusInfo, previous = false, num = 1) {
|
322
322
|
|
323
|
-
const curListItem = findComposedAncestor(this, node => node.role === '
|
323
|
+
const curListItem = findComposedAncestor(this, node => node.role === 'row');
|
324
324
|
let listItem = curListItem;
|
325
325
|
|
326
326
|
while (num > 0) {
|
@@ -331,7 +331,7 @@ class ListItemGenericLayout extends RtlMixin(LitElement) {
|
|
331
331
|
}
|
332
332
|
|
333
333
|
if (!listItem) return;
|
334
|
-
const listItemRow = listItem.shadowRoot.querySelector('[role="
|
334
|
+
const listItemRow = listItem.shadowRoot.querySelector('[role="gridcell"]');
|
335
335
|
const focusedCellItem = listItemRow._focusCellItem(focusInfo);
|
336
336
|
|
337
337
|
if (!focusedCellItem) {
|
@@ -339,7 +339,7 @@ class ListItemGenericLayout extends RtlMixin(LitElement) {
|
|
339
339
|
if (!listItem._tryFocus()) {
|
340
340
|
// ultimate fallback to generic method for getting next/previous focusable
|
341
341
|
const nextFocusable = previous ? getPreviousFocusable(listItem) : getNextFocusable(listItem);
|
342
|
-
const nextListItem = findComposedAncestor(nextFocusable, (node) => node.role === '
|
342
|
+
const nextListItem = findComposedAncestor(nextFocusable, (node) => node.role === 'row' || node.role === 'listitem');
|
343
343
|
if (nextListItem && this._isContainedInSameRootList(curListItem, nextListItem)) {
|
344
344
|
nextFocusable.focus();
|
345
345
|
}
|
@@ -363,7 +363,7 @@ class ListItemGenericLayout extends RtlMixin(LitElement) {
|
|
363
363
|
// check for nested list first; this check needs to account for standard list-items as well as custom
|
364
364
|
const nestedList = listItem.querySelector('[slot="nested"]') || listItem.shadowRoot.querySelector('d2l-list');
|
365
365
|
if (nestedList && (!listItem.expandable || (listItem.expandable && listItem.expanded))) {
|
366
|
-
const nestedListItem = [...nestedList.children].find(node => node.role === '
|
366
|
+
const nestedListItem = [...nestedList.children].find(node => node.role === 'row');
|
367
367
|
if (nestedListItem) return nestedListItem;
|
368
368
|
}
|
369
369
|
|
@@ -372,7 +372,7 @@ class ListItemGenericLayout extends RtlMixin(LitElement) {
|
|
372
372
|
// check for sibling list-item
|
373
373
|
let nextElement = listItem.nextElementSibling;
|
374
374
|
while (nextElement) {
|
375
|
-
if (nextElement.role === '
|
375
|
+
if (nextElement.role === 'row') return nextElement;
|
376
376
|
nextElement = nextElement.nextElementSibling;
|
377
377
|
}
|
378
378
|
|
@@ -380,7 +380,7 @@ class ListItemGenericLayout extends RtlMixin(LitElement) {
|
|
380
380
|
const list = findComposedAncestor(listItem, node => node.tagName === 'D2L-LIST');
|
381
381
|
if (list.slot !== 'nested' && !(list.parentNode.tagName === 'SLOT' && list.parentNode.name === 'nested')) return;
|
382
382
|
|
383
|
-
const parentListItem = findComposedAncestor(list, node => node.role === '
|
383
|
+
const parentListItem = findComposedAncestor(list, node => node.role === 'row');
|
384
384
|
return getNextListItem(parentListItem);
|
385
385
|
|
386
386
|
};
|
@@ -396,14 +396,14 @@ class ListItemGenericLayout extends RtlMixin(LitElement) {
|
|
396
396
|
|
397
397
|
// try to get the previous list-item in the current list sub-tree including nested
|
398
398
|
while (previousElement) {
|
399
|
-
if (previousElement.role === '
|
399
|
+
if (previousElement.role === 'row') {
|
400
400
|
|
401
401
|
let nestedList;
|
402
402
|
do {
|
403
403
|
// this check needs to account for standard list-items as well as custom
|
404
404
|
nestedList = previousElement.querySelector('[slot="nested"]') || previousElement.shadowRoot.querySelector('d2l-list');
|
405
405
|
if (nestedList) {
|
406
|
-
const nestedListItems = [...nestedList.children].filter(node => node.role === '
|
406
|
+
const nestedListItems = [...nestedList.children].filter(node => node.role === 'row');
|
407
407
|
if (nestedListItems.length) {
|
408
408
|
previousElement = nestedListItems[nestedListItems.length - 1];
|
409
409
|
} else {
|
@@ -421,7 +421,7 @@ class ListItemGenericLayout extends RtlMixin(LitElement) {
|
|
421
421
|
|
422
422
|
// this check needs to account for standard list-items as well as custom
|
423
423
|
if (list.slot === 'nested' || (list.parentNode.tagName === 'SLOT' && list.parentNode.name === 'nested')) {
|
424
|
-
const parentListItem = findComposedAncestor(list, node => node.role === '
|
424
|
+
const parentListItem = findComposedAncestor(list, node => node.role === 'row');
|
425
425
|
return parentListItem;
|
426
426
|
}
|
427
427
|
|
@@ -460,7 +460,7 @@ export const ListItemMixin = superclass => class extends composeMixins(
|
|
460
460
|
|
461
461
|
connectedCallback() {
|
462
462
|
super.connectedCallback();
|
463
|
-
if (this.role === '
|
463
|
+
if (this.role === 'row') {
|
464
464
|
addTabListener();
|
465
465
|
}
|
466
466
|
if (!this.selectable && !this.expandable) {
|
@@ -599,12 +599,12 @@ export const ListItemMixin = superclass => class extends composeMixins(
|
|
599
599
|
|
600
600
|
_isListItem(node) {
|
601
601
|
if (!node) node = this;
|
602
|
-
return node.role === '
|
602
|
+
return node.role === 'row' || node.role === 'listitem';
|
603
603
|
}
|
604
604
|
|
605
605
|
_onFocusIn() {
|
606
606
|
this._focusing = true;
|
607
|
-
if (this.role !== '
|
607
|
+
if (this.role !== 'row' || !tabPressed || hasDisplayedKeyboardTooltip) return;
|
608
608
|
this._displayKeyboardTooltip = true;
|
609
609
|
hasDisplayedKeyboardTooltip = true;
|
610
610
|
}
|
@@ -696,7 +696,7 @@ export const ListItemMixin = superclass => class extends composeMixins(
|
|
696
696
|
@focusout="${this._onFocusOut}"
|
697
697
|
class="${classMap(classes)}"
|
698
698
|
data-separators="${ifDefined(this._separators)}"
|
699
|
-
?grid-active="${this.role === '
|
699
|
+
?grid-active="${this.role === 'row'}"
|
700
700
|
?no-primary-action="${this.noPrimaryAction}">
|
701
701
|
${this._showAddButton && this.first ? html`
|
702
702
|
<div slot="add-top">
|
@@ -27,7 +27,7 @@ export const ListItemRoleMixin = superclass => class extends superclass {
|
|
27
27
|
|
28
28
|
const separators = parent.getAttribute('separators');
|
29
29
|
|
30
|
-
this.role = parent.hasAttribute('grid') ? '
|
30
|
+
this.role = parent.hasAttribute('grid') ? 'row' : 'listitem';
|
31
31
|
this._nested = (parent.slot === 'nested');
|
32
32
|
this._separators = separators || undefined;
|
33
33
|
this._extendSeparators = parent.hasAttribute('extend-separators');
|
package/components/list/list.js
CHANGED
@@ -205,7 +205,7 @@ class List extends PageableMixin(SelectionMixin(LitElement)) {
|
|
205
205
|
}
|
206
206
|
|
207
207
|
render() {
|
208
|
-
const role = !this.grid ? 'list' : 'application';
|
208
|
+
const role = !this.grid ? 'list' : 'application'; // not using grid role due to Safari+VO: https://bugs.webkit.org/show_bug.cgi?id=291591
|
209
209
|
const ariaLabel = this.slot !== 'nested' ? this.label : undefined;
|
210
210
|
return html`
|
211
211
|
<slot name="controls"></slot>
|
@@ -235,7 +235,7 @@ class List extends PageableMixin(SelectionMixin(LitElement)) {
|
|
235
235
|
if (!slot) slot = this.shadowRoot.querySelector('slot:not([name])');
|
236
236
|
if (!slot) return [];
|
237
237
|
return slot.assignedNodes({ flatten: true }).filter((node) => {
|
238
|
-
return node.nodeType === Node.ELEMENT_NODE && (node.role === '
|
238
|
+
return node.nodeType === Node.ELEMENT_NODE && (node.role === 'row' || node.role === 'listitem');
|
239
239
|
});
|
240
240
|
}
|
241
241
|
|
package/custom-elements.json
CHANGED
@@ -5113,6 +5113,17 @@
|
|
5113
5113
|
}
|
5114
5114
|
]
|
5115
5115
|
},
|
5116
|
+
{
|
5117
|
+
"name": "d2l-input-checkbox-group",
|
5118
|
+
"path": "./components/inputs/input-checkbox-group.js",
|
5119
|
+
"description": "A wrapper for <d2l-input-checkbox> components which provides spacing between the items.",
|
5120
|
+
"slots": [
|
5121
|
+
{
|
5122
|
+
"name": "",
|
5123
|
+
"description": "Checkbox components"
|
5124
|
+
}
|
5125
|
+
]
|
5126
|
+
},
|
5116
5127
|
{
|
5117
5128
|
"name": "d2l-input-checkbox",
|
5118
5129
|
"path": "./components/inputs/input-checkbox.js",
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@brightspace-ui/core",
|
3
|
-
"version": "3.
|
3
|
+
"version": "3.110.1",
|
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",
|