@brightspace-ui/core 3.225.0 → 3.226.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.
@@ -2,10 +2,12 @@ import '../colors/colors.js';
2
2
  import { css, html, LitElement } from 'lit';
3
3
  import { cssEscape, getComposedChildren, getComposedParent, isComposedAncestor, isVisible } from '../../helpers/dom.js';
4
4
  import { getComposedActiveElement } from '../../helpers/focus.js';
5
+ import { getFlag } from '../../helpers/flags.js';
5
6
 
6
7
  const BACKDROP_HIDDEN = 'data-d2l-backdrop-hidden';
7
8
  const BACKDROP_ARIA_HIDDEN = 'data-d2l-backdrop-aria-hidden';
8
9
  const BACKDROP_TABINDEX = 'data-d2l-backdrop-tabindex';
10
+ const BACKDROP_INERT = 'data-d2l-backdrop-inert';
9
11
  const TRANSITION_DURATION = 200;
10
12
 
11
13
  const reduceMotion = matchMedia('(prefers-reduced-motion: reduce)').matches;
@@ -180,6 +182,13 @@ function hideAccessible(target) {
180
182
  }
181
183
  child.setAttribute('tabindex', '-1');
182
184
 
185
+ if (getFlag('GAUD-9398-make-backdrop-inert', false)) {
186
+ if (child.hasAttribute('inert')) {
187
+ child.setAttribute(BACKDROP_INERT, '');
188
+ }
189
+ child.setAttribute('inert', '');
190
+ }
191
+
183
192
  child.setAttribute(BACKDROP_HIDDEN, BACKDROP_HIDDEN);
184
193
  hiddenElements.push(child);
185
194
  }
@@ -213,6 +222,13 @@ function showAccessible(elems) {
213
222
  } else {
214
223
  elem.removeAttribute('tabindex');
215
224
  }
225
+ if (getFlag('GAUD-9398-make-backdrop-inert', false)) {
226
+ if (elem.hasAttribute(BACKDROP_INERT)) {
227
+ elem.removeAttribute(BACKDROP_INERT);
228
+ } else {
229
+ elem.removeAttribute('inert');
230
+ }
231
+ }
216
232
  elem.removeAttribute(BACKDROP_HIDDEN);
217
233
  }
218
234
  }
@@ -360,7 +360,7 @@ Use the Copy button to enable users to copy a text value to the clipboard. The `
360
360
  |--|--|--|
361
361
  | `disabled` | Boolean | Disables the button |
362
362
  | `description` | String | A description to be added to the button for accessibility when text on button does not provide enough context |
363
- | `silm` | Boolean | Makes the button slimmer |
363
+ | `slim` | Boolean | Makes the button slimmer |
364
364
  | `text` | String | Label text for the button |
365
365
  <!-- docs: end hidden content -->
366
366
 
@@ -1,6 +1,9 @@
1
- import { findComposedAncestor, getComposedParent, isComposedAncestor } from '../../helpers/dom.js';
1
+ import { addResizeNoopEventListener, findComposedAncestor, getComposedParent, isComposedAncestor, removeResizeNoopEventListener } from '../../helpers/dom.js';
2
2
  import { getNextFocusable, getPreviousFocusable } from '../../helpers/focus.js';
3
3
  import { css } from 'lit';
4
+ import { getFlag } from '../../helpers/flags.js';
5
+
6
+ const ignoreNoopResizeEventsFlag = getFlag('GAUD-9520-ignore-no-op-resize-events', true);
4
7
 
5
8
  const reduceMotion = matchMedia('(prefers-reduced-motion: reduce)').matches;
6
9
  const __nativeFocus = document.createElement('div').focus;
@@ -141,7 +144,11 @@ export const HierarchicalViewMixin = superclass => class extends superclass {
141
144
  this.addEventListener('focus', this.__focusCapture, true);
142
145
  this.addEventListener('focusout', this.__focusOutCapture, true);
143
146
  this.__onWindowResize = this.__onWindowResize.bind(this);
144
- window.addEventListener('resize', this.__onWindowResize);
147
+ if (ignoreNoopResizeEventsFlag) {
148
+ addResizeNoopEventListener(this.__onWindowResize);
149
+ } else {
150
+ window.addEventListener('resize', this.__onWindowResize);
151
+ }
145
152
  }
146
153
  });
147
154
  }
@@ -151,7 +158,12 @@ export const HierarchicalViewMixin = superclass => class extends superclass {
151
158
 
152
159
  this.removeEventListener('focus', this.__focusCapture);
153
160
  this.removeEventListener('focusout', this.__focusOutCapture);
154
- window.removeEventListener('resize', this.__onWindowResize);
161
+ if (ignoreNoopResizeEventsFlag) {
162
+ removeResizeNoopEventListener(this.__onWindowResize);
163
+ } else {
164
+ window.removeEventListener('resize', this.__onWindowResize);
165
+ }
166
+
155
167
  if (this.__intersectionObserver) {
156
168
  this.__intersectionObserver.disconnect();
157
169
  this.__isAutoSized = false;
@@ -58,7 +58,19 @@
58
58
  <d2l-demo-snippet>
59
59
  <template>
60
60
  <d2l-input-checkbox label="Label for checkbox">
61
- <div slot="supporting" style="color: #999999;">
61
+ <div slot="supporting">
62
+ Additional content can go here and will<br>
63
+ also line up nicely with the checkbox.
64
+ </div>
65
+ </d2l-input-checkbox>
66
+ </template>
67
+ </d2l-demo-snippet>
68
+
69
+ <h2>Checkbox with label and supporting content with progressive disclosure</h2>
70
+ <d2l-demo-snippet>
71
+ <template>
72
+ <d2l-input-checkbox label="Toggle content with checkbox" supporting-hidden-when-unchecked>
73
+ <div slot="supporting">
62
74
  Additional content can go here and will<br>
63
75
  also line up nicely with the checkbox.
64
76
  </div>
@@ -88,6 +88,7 @@ When provided with a `name`, the checkbox will participate in forms if it is `ch
88
88
  | `label-hidden` | Boolean | Hides the label visually (moves it to the input's `aria-label` attribute) |
89
89
  | `name` | String | Name of the form control. Submitted with the form as part of a name/value pair. |
90
90
  | `not-tabbable` | Boolean | Sets `tabindex="-1"` on the checkbox. Note that an alternative method of focusing is necessary to implement if using this property. |
91
+ | `supporting-hidden-when-unchecked` | Boolean | Hides the supporting slot when unchecked. |
91
92
  | `value` | String | Value of the input |
92
93
 
93
94
  ### Events
@@ -176,6 +176,11 @@ class InputCheckbox extends FormElementMixin(InputInlineHelpMixin(FocusMixin(Ske
176
176
  * @type {boolean}
177
177
  */
178
178
  notTabbable: { type: Boolean, attribute: 'not-tabbable' },
179
+ /**
180
+ * Hides the supporting slot when unchecked
181
+ * @type {boolean}
182
+ */
183
+ supportingHiddenWhenUnchecked: { type: Boolean, attribute: 'supporting-hidden-when-unchecked', reflect: true },
179
184
  /**
180
185
  * Value of the input
181
186
  * @type {string}
@@ -254,6 +259,7 @@ class InputCheckbox extends FormElementMixin(InputInlineHelpMixin(FocusMixin(Ske
254
259
  this.labelHidden = false;
255
260
  this.name = '';
256
261
  this.notTabbable = false;
262
+ this.supportingHiddenWhenUnchecked = false;
257
263
  this.value = 'on';
258
264
  this._hasSupporting = false;
259
265
  this._isHovered = false;
@@ -267,7 +273,7 @@ class InputCheckbox extends FormElementMixin(InputInlineHelpMixin(FocusMixin(Ske
267
273
  const tabindex = this.notTabbable ? -1 : undefined;
268
274
  const supportingClasses = {
269
275
  'd2l-input-checkbox-supporting': true,
270
- 'd2l-input-checkbox-supporting-visible': this._hasSupporting
276
+ 'd2l-input-checkbox-supporting-visible': this._hasSupporting && (this.checked || !this.supportingHiddenWhenUnchecked)
271
277
  };
272
278
  const textClasses = {
273
279
  'd2l-input-checkbox-text': true,
@@ -1,15 +1,18 @@
1
1
  import '../backdrop/backdrop.js';
2
2
  import '../colors/colors.js';
3
3
  import '../focus-trap/focus-trap.js';
4
+ import { addResizeNoopEventListener, getComposedParent, isComposedAncestor, removeResizeNoopEventListener } from '../../helpers/dom.js';
4
5
  import { clearDismissible, setDismissible } from '../../helpers/dismissible.js';
5
6
  import { css, html, nothing } from 'lit';
6
7
  import { getComposedActiveElement, getFirstFocusableDescendant, getPreviousFocusableAncestor } from '../../helpers/focus.js';
7
- import { getComposedParent, isComposedAncestor } from '../../helpers/dom.js';
8
8
  import { _offscreenStyleDeclarations } from '../offscreen/offscreen.js';
9
9
  import { classMap } from 'lit/directives/class-map.js';
10
+ import { getFlag } from '../../helpers/flags.js';
10
11
  import { styleMap } from 'lit/directives/style-map.js';
11
12
  import { tryGetIfrauBackdropService } from '../../helpers/ifrauBackdropService.js';
12
13
 
14
+ const ignoreNoopResizeEventsFlag = getFlag('GAUD-9520-ignore-no-op-resize-events', true);
15
+
13
16
  export const positionLocations = Object.freeze({
14
17
  blockEnd: 'block-end',
15
18
  blockStart: 'block-start',
@@ -612,7 +615,11 @@ export const PopoverMixin = superclass => class extends superclass {
612
615
  this.#removeRepositionHandlers();
613
616
  this.#ancestorMutations = new Map();
614
617
 
615
- window.addEventListener('resize', this.#handleResizeBound);
618
+ if (ignoreNoopResizeEventsFlag) {
619
+ addResizeNoopEventListener(this.#handleResizeBound);
620
+ } else {
621
+ window.addEventListener('resize', this.#handleResizeBound);
622
+ }
616
623
 
617
624
  this._ancestorMutationObserver ??= new MutationObserver(this.#handleAncestorMutationBound);
618
625
  const mutationConfig = { attributes: true, childList: true, subtree: true };
@@ -1186,7 +1193,11 @@ export const PopoverMixin = superclass => class extends superclass {
1186
1193
  });
1187
1194
  this._scrollablesObserved = null;
1188
1195
  this._ancestorMutationObserver?.disconnect();
1189
- window.removeEventListener('resize', this.#handleResizeBound);
1196
+ if (ignoreNoopResizeEventsFlag) {
1197
+ removeResizeNoopEventListener(this.#handleResizeBound);
1198
+ } else {
1199
+ window.removeEventListener('resize', this.#handleResizeBound);
1200
+ }
1190
1201
  }
1191
1202
 
1192
1203
  #reposition() {
@@ -5407,6 +5407,12 @@
5407
5407
  "type": "boolean",
5408
5408
  "default": "false"
5409
5409
  },
5410
+ {
5411
+ "name": "supporting-hidden-when-unchecked",
5412
+ "description": "Hides the supporting slot when unchecked",
5413
+ "type": "boolean",
5414
+ "default": "false"
5415
+ },
5410
5416
  {
5411
5417
  "name": "value",
5412
5418
  "description": "Value of the input",
@@ -5480,6 +5486,13 @@
5480
5486
  "type": "boolean",
5481
5487
  "default": "false"
5482
5488
  },
5489
+ {
5490
+ "name": "supportingHiddenWhenUnchecked",
5491
+ "attribute": "supporting-hidden-when-unchecked",
5492
+ "description": "Hides the supporting slot when unchecked",
5493
+ "type": "boolean",
5494
+ "default": "false"
5495
+ },
5483
5496
  {
5484
5497
  "name": "value",
5485
5498
  "attribute": "value",
package/helpers/dom.js CHANGED
@@ -263,3 +263,41 @@ export function querySelectorComposed(node, selector) {
263
263
 
264
264
  return null;
265
265
  }
266
+
267
+ const resizeNoopEventListener = new Set();
268
+ const resizeNoopRect = {};
269
+
270
+ if (globalThis.addEventListener) {
271
+ globalThis.addEventListener('resize', e => {
272
+ if (resizeNoopEventListener.size === 0) return;
273
+
274
+ const frameElement = e.target.frameElement;
275
+ if (frameElement?.classList.contains('d2l-iframe-fit-user-content')) {
276
+ // ignore if the iframe is spamming no-op resize events
277
+ if (resizeNoopRect.height === frameElement.scrollHeight && resizeNoopRect.width === frameElement.scrollWidth) {
278
+ return;
279
+ }
280
+ resizeNoopRect.height = frameElement.scrollHeight;
281
+ resizeNoopRect.width = frameElement.scrollWidth;
282
+ }
283
+
284
+ resizeNoopEventListener.forEach(listener => {
285
+ listener(e);
286
+ });
287
+ });
288
+ }
289
+
290
+ export function addResizeNoopEventListener(listener) {
291
+ resizeNoopEventListener.add(listener);
292
+ resizeNoopRect.height = null;
293
+ resizeNoopRect.width = null;
294
+ }
295
+
296
+ export function removeResizeNoopEventListener(listener) {
297
+ resizeNoopEventListener.delete(listener);
298
+ }
299
+
300
+ // testing only
301
+ export function clearResizeNoopEventListeners() {
302
+ resizeNoopEventListener.clear();
303
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brightspace-ui/core",
3
- "version": "3.225.0",
3
+ "version": "3.226.0",
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",