@brightspace-ui/core 3.225.1 → 3.227.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.
- package/components/button/README.md +1 -1
- package/components/hierarchical-view/hierarchical-view-mixin.js +15 -3
- package/components/inputs/demo/input-checkbox.html +13 -1
- package/components/inputs/docs/input-checkbox.md +1 -0
- package/components/inputs/input-checkbox.js +11 -9
- package/components/inputs/input-radio.js +5 -9
- package/components/popover/popover-mixin.js +14 -3
- package/custom-elements.json +13 -0
- package/helpers/dom.js +38 -0
- package/package.json +1 -1
|
@@ -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
|
-
| `
|
|
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
|
-
|
|
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
|
-
|
|
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"
|
|
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
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import '../colors/colors.js';
|
|
2
|
+
import '../expand-collapse/expand-collapse-content.js';
|
|
2
3
|
import '../tooltip/tooltip.js';
|
|
3
4
|
import { css, html, LitElement, nothing } from 'lit';
|
|
4
5
|
import { classMap } from 'lit/directives/class-map.js';
|
|
@@ -176,6 +177,11 @@ class InputCheckbox extends FormElementMixin(InputInlineHelpMixin(FocusMixin(Ske
|
|
|
176
177
|
* @type {boolean}
|
|
177
178
|
*/
|
|
178
179
|
notTabbable: { type: Boolean, attribute: 'not-tabbable' },
|
|
180
|
+
/**
|
|
181
|
+
* Hides the supporting slot when unchecked
|
|
182
|
+
* @type {boolean}
|
|
183
|
+
*/
|
|
184
|
+
supportingHiddenWhenUnchecked: { type: Boolean, attribute: 'supporting-hidden-when-unchecked', reflect: true },
|
|
179
185
|
/**
|
|
180
186
|
* Value of the input
|
|
181
187
|
* @type {string}
|
|
@@ -235,12 +241,8 @@ class InputCheckbox extends FormElementMixin(InputInlineHelpMixin(FocusMixin(Ske
|
|
|
235
241
|
vertical-align: top;
|
|
236
242
|
}
|
|
237
243
|
.d2l-input-checkbox-supporting {
|
|
238
|
-
display: none;
|
|
239
244
|
margin-block-start: 0.6rem;
|
|
240
245
|
}
|
|
241
|
-
.d2l-input-checkbox-supporting-visible {
|
|
242
|
-
display: block;
|
|
243
|
-
}
|
|
244
246
|
`
|
|
245
247
|
];
|
|
246
248
|
}
|
|
@@ -254,6 +256,7 @@ class InputCheckbox extends FormElementMixin(InputInlineHelpMixin(FocusMixin(Ske
|
|
|
254
256
|
this.labelHidden = false;
|
|
255
257
|
this.name = '';
|
|
256
258
|
this.notTabbable = false;
|
|
259
|
+
this.supportingHiddenWhenUnchecked = false;
|
|
257
260
|
this.value = 'on';
|
|
258
261
|
this._hasSupporting = false;
|
|
259
262
|
this._isHovered = false;
|
|
@@ -265,10 +268,7 @@ class InputCheckbox extends FormElementMixin(InputInlineHelpMixin(FocusMixin(Ske
|
|
|
265
268
|
|
|
266
269
|
render() {
|
|
267
270
|
const tabindex = this.notTabbable ? -1 : undefined;
|
|
268
|
-
const
|
|
269
|
-
'd2l-input-checkbox-supporting': true,
|
|
270
|
-
'd2l-input-checkbox-supporting-visible': this._hasSupporting
|
|
271
|
-
};
|
|
271
|
+
const supportingContentVisible = this._hasSupporting && (this.checked || !this.supportingHiddenWhenUnchecked);
|
|
272
272
|
const textClasses = {
|
|
273
273
|
'd2l-input-checkbox-text': true,
|
|
274
274
|
'd2l-skeletize': true,
|
|
@@ -305,7 +305,9 @@ class InputCheckbox extends FormElementMixin(InputInlineHelpMixin(FocusMixin(Ske
|
|
|
305
305
|
${this._renderInlineHelp(this.#inlineHelpId)}
|
|
306
306
|
${offscreenContainer}
|
|
307
307
|
${disabledTooltip}
|
|
308
|
-
<
|
|
308
|
+
<d2l-expand-collapse-content ?expanded="${supportingContentVisible}">
|
|
309
|
+
<div class="d2l-input-checkbox-supporting" @change="${this.#handleSupportingChange}"><slot name="supporting" @slotchange="${this.#handleSupportingSlotChange}"></slot></div>
|
|
310
|
+
</d2l-expand-collapse-content>
|
|
309
311
|
`;
|
|
310
312
|
}
|
|
311
313
|
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import '../expand-collapse/expand-collapse-content.js';
|
|
1
2
|
import '../tooltip/tooltip.js';
|
|
2
3
|
import { css, html, LitElement, nothing } from 'lit';
|
|
3
4
|
import { classMap } from 'lit/directives/class-map.js';
|
|
@@ -80,12 +81,8 @@ class InputRadio extends InputInlineHelpMixin(SkeletonMixin(FocusMixin(PropertyR
|
|
|
80
81
|
margin-inline-start: 1.7rem;
|
|
81
82
|
}
|
|
82
83
|
.d2l-input-radio-supporting {
|
|
83
|
-
display: none;
|
|
84
84
|
margin-block-start: 0.6rem;
|
|
85
85
|
}
|
|
86
|
-
.d2l-input-radio-supporting-visible {
|
|
87
|
-
display: block;
|
|
88
|
-
}
|
|
89
86
|
`];
|
|
90
87
|
}
|
|
91
88
|
|
|
@@ -129,6 +126,7 @@ class InputRadio extends InputInlineHelpMixin(SkeletonMixin(FocusMixin(PropertyR
|
|
|
129
126
|
|
|
130
127
|
render() {
|
|
131
128
|
const allowFocus = !this.focusDisabled && this._focusable;
|
|
129
|
+
const supportingContentVisible = this._hasSupporting && (!this.supportingHiddenWhenUnchecked || this._checked);
|
|
132
130
|
const labelStyles = {
|
|
133
131
|
alignItems: this._horizontal ? 'flex-start' : undefined
|
|
134
132
|
};
|
|
@@ -143,10 +141,6 @@ class InputRadio extends InputInlineHelpMixin(SkeletonMixin(FocusMixin(PropertyR
|
|
|
143
141
|
'd2l-hovering': this._isHovered && !this.focusDisabled,
|
|
144
142
|
'd2l-skeletize': true
|
|
145
143
|
};
|
|
146
|
-
const supportingClasses = {
|
|
147
|
-
'd2l-input-radio-supporting': true,
|
|
148
|
-
'd2l-input-radio-supporting-visible': this._hasSupporting && (!this.supportingHiddenWhenUnchecked || this._checked),
|
|
149
|
-
};
|
|
150
144
|
const description = this.description ? html`<div id="${this.#descriptionId}" hidden>${this.description}</div>` : nothing;
|
|
151
145
|
const ariaDescribedByIds = `${this.description ? this.#descriptionId : ''} ${this._hasInlineHelp ? this.#inlineHelpId : ''}`.trim();
|
|
152
146
|
const disabledTooltip = this.disabled && this.disabledTooltip ?
|
|
@@ -169,7 +163,9 @@ class InputRadio extends InputInlineHelpMixin(SkeletonMixin(FocusMixin(PropertyR
|
|
|
169
163
|
${this._renderInlineHelp(this.#inlineHelpId)}
|
|
170
164
|
${description}
|
|
171
165
|
${disabledTooltip}
|
|
172
|
-
<
|
|
166
|
+
<d2l-expand-collapse-content ?expanded="${supportingContentVisible}">
|
|
167
|
+
<div class="d2l-input-radio-supporting" @change="${this.#handleSupportingChange}"><slot name="supporting" @slotchange="${this.#handleSupportingSlotChange}"></slot></div>
|
|
168
|
+
</d2l-expand-collapse-content>
|
|
173
169
|
`;
|
|
174
170
|
}
|
|
175
171
|
|
|
@@ -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
|
-
|
|
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
|
-
|
|
1196
|
+
if (ignoreNoopResizeEventsFlag) {
|
|
1197
|
+
removeResizeNoopEventListener(this.#handleResizeBound);
|
|
1198
|
+
} else {
|
|
1199
|
+
window.removeEventListener('resize', this.#handleResizeBound);
|
|
1200
|
+
}
|
|
1190
1201
|
}
|
|
1191
1202
|
|
|
1192
1203
|
#reposition() {
|
package/custom-elements.json
CHANGED
|
@@ -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.
|
|
3
|
+
"version": "3.227.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",
|