@brightspace-ui/core 3.73.0 → 3.73.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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",