@brightspace-ui/core 3.73.0 → 3.73.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.
@@ -1,6 +1,6 @@
1
1
  # Backdrops
2
2
 
3
- The `d2l-backdrop` element is a web component to display a semi-transparent backdrop behind a specified sibling element. It also hides elements other than the target from assistive technologies by applying `role="presentation"` and `aria-hidden="true"`.
3
+ The `d2l-backdrop` element displays a semi-transparent backdrop behind a specified sibling target element. It also hides elements other than the target from assistive technologies by applying `aria-hidden="true"`.
4
4
 
5
5
  ## Backdrop [d2l-backdrop]
6
6
 
@@ -9,7 +9,6 @@ The `d2l-backdrop` element is a web component to display a semi-transparent back
9
9
  <script type="module">
10
10
  import '@brightspace-ui/core/components/button/button.js';
11
11
  import '@brightspace-ui/core/components/backdrop/backdrop.js';
12
- import '@brightspace-ui/core/components/switch/switch.js';
13
12
 
14
13
  const backdrop = document.querySelector('d2l-backdrop');
15
14
  document.querySelector('#target > d2l-button').addEventListener('click', () => {
@@ -36,3 +35,11 @@ The `d2l-backdrop` element is a web component to display a semi-transparent back
36
35
  | `shown` | Boolean | Used to control whether the backdrop is shown |
37
36
  | `slow-transition` | Boolean | Increases the fade transition time to 1200ms (default is 200ms) |
38
37
  <!-- docs: end hidden content -->
38
+
39
+ ### Focus Management
40
+
41
+ Elements with `aria-hidden` applied (as well as their descendants) are completely hidden from assistive technologies. It's therefore very important that the element with active focus be within the backdrop target.
42
+
43
+ **When showing a backdrop**: first move focus inside the target, then set the `shown` attribute on the backdrop.
44
+
45
+ **When hiding a backdrop**: first remove the `shown` attribute on the backdrop, then if appropriate move focus outside the target.
@@ -1,6 +1,7 @@
1
1
  import '../colors/colors.js';
2
2
  import { css, html, LitElement } from 'lit';
3
- import { cssEscape, getComposedChildren, getComposedParent, isVisible } from '../../helpers/dom.js';
3
+ import { cssEscape, getComposedChildren, getComposedParent, isComposedAncestor, isVisible } from '../../helpers/dom.js';
4
+ import { getComposedActiveElement } from '../../helpers/focus.js';
4
5
 
5
6
  const BACKDROP_HIDDEN = 'data-d2l-backdrop-hidden';
6
7
  const BACKDROP_ARIA_HIDDEN = 'data-d2l-backdrop-aria-hidden';
@@ -12,7 +13,7 @@ const modals = new Set();
12
13
  let scrollOverflow = null;
13
14
 
14
15
  /**
15
- * A component for displaying a semi-transparent backdrop behind a specified sibling element. It also hides elements other than the target from assistive technologies by applying 'role="presentation"' and 'aria-hidden="true"'.
16
+ * A component for displaying a semi-transparent backdrop behind a specified sibling element. It also hides elements other than the target from assistive technologies by applying 'aria-hidden="true"'.
16
17
  */
17
18
  class Backdrop extends LitElement {
18
19
 
@@ -85,10 +86,8 @@ class Backdrop extends LitElement {
85
86
  disconnectedCallback() {
86
87
  // allow body scrolling, show hidden elements, if backdrop is removed from the DOM
87
88
  allowBodyScroll(this);
88
- if (this._hiddenElements) {
89
- showAccessible(this._hiddenElements);
90
- this._hiddenElements = null;
91
- }
89
+ showAccessible(this._hiddenElements);
90
+ this._hiddenElements = null;
92
91
  this._state = null;
93
92
  super.disconnectedCallback();
94
93
  }
@@ -106,7 +105,12 @@ class Backdrop extends LitElement {
106
105
 
107
106
  if (this._state === null) {
108
107
  preventBodyScroll(this);
109
- this._hiddenElements = hideAccessible(this.parentNode.querySelector(`#${cssEscape(this.forTarget)}`));
108
+ const target = this.parentNode.querySelector(`#${cssEscape(this.forTarget)}`);
109
+ // aria-hidden elements cannot have focus, so wait for focus to be within target
110
+ waitForFocusWithinTarget(target, Date.now() + 200).then(() => {
111
+ if (!this.shown || this._state !== 'showing') return;
112
+ this._hiddenElements = hideAccessible(target);
113
+ });
110
114
  }
111
115
  this._state = 'showing';
112
116
 
@@ -188,6 +192,7 @@ function hideAccessible(target) {
188
192
  }
189
193
 
190
194
  function showAccessible(elems) {
195
+ if (!elems) return;
191
196
  for (let i = 0; i < elems.length; i++) {
192
197
  const elem = elems[i];
193
198
  if (elem.hasAttribute(BACKDROP_ARIA_HIDDEN)) {
@@ -200,4 +205,18 @@ function showAccessible(elems) {
200
205
  }
201
206
  }
202
207
 
208
+ async function waitForFocusWithinTarget(target, expireTime) {
209
+
210
+ if (Date.now() > expireTime) return;
211
+
212
+ const activeElem = getComposedActiveElement();
213
+ const targetIsAncestor = isComposedAncestor(target, activeElem);
214
+
215
+ if (targetIsAncestor) return;
216
+
217
+ await new Promise(resolve => requestAnimationFrame(resolve));
218
+ return waitForFocusWithinTarget(target, expireTime);
219
+
220
+ }
221
+
203
222
  customElements.define('d2l-backdrop', Backdrop);
@@ -189,7 +189,7 @@
189
189
  {
190
190
  "name": "d2l-backdrop",
191
191
  "path": "./components/backdrop/backdrop.js",
192
- "description": "A component for displaying a semi-transparent backdrop behind a specified sibling element. It also hides elements other than the target from assistive technologies by applying 'role=\"presentation\"' and 'aria-hidden=\"true\"'.",
192
+ "description": "A component for displaying a semi-transparent backdrop behind a specified sibling element. It also hides elements other than the target from assistive technologies by applying 'aria-hidden=\"true\"'.",
193
193
  "attributes": [
194
194
  {
195
195
  "name": "for-target",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brightspace-ui/core",
3
- "version": "3.73.0",
3
+ "version": "3.73.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",