@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.
@@ -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 label="Checked item" checked></d2l-input-checkbox>
19
- <d2l-input-checkbox label="Unchecked item"></d2l-input-checkbox>
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 style="overflow: hidden; width: 200px;" label="Label for checkbox that wraps nicely onto multiple lines and stays aligned"></d2l-input-checkbox>
27
- <d2l-input-checkbox style="overflow: hidden; width: 200px;" label="https://en.wikipedia.org/wiki/Dark_matter"></d2l-input-checkbox>
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', function () {
40
- var input = document.querySelector('#checkbox');
41
- input.addEventListener('change', (e) => {
42
- console.log('checked value: ', input.checked);
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 id="checkbox" label="Label for checkbox"></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', (e) => {
73
- console.log(checkbox.checked);
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 ? 'gridrow' : undefined;
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="gridrow"]');
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="gridrow"]');
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 === 'rowgroup');
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="gridrow"]');
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 === 'rowgroup' || node.role === 'listitem');
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 === 'rowgroup');
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 === 'rowgroup') return nextElement;
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 === 'rowgroup');
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 === 'rowgroup') {
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 === 'rowgroup');
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 === 'rowgroup');
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 === 'rowgroup') {
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 === 'rowgroup' || node.role === 'listitem';
602
+ return node.role === 'row' || node.role === 'listitem';
603
603
  }
604
604
 
605
605
  _onFocusIn() {
606
606
  this._focusing = true;
607
- if (this.role !== 'rowgroup' || !tabPressed || hasDisplayedKeyboardTooltip) return;
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 === 'rowgroup'}"
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') ? 'rowgroup' : 'listitem';
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');
@@ -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 === 'rowgroup' || node.role === 'listitem');
238
+ return node.nodeType === Node.ELEMENT_NODE && (node.role === 'row' || node.role === 'listitem');
239
239
  });
240
240
  }
241
241
 
@@ -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.109.0",
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",