@brightspace-ui/core 3.25.0 → 3.25.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.
@@ -100,10 +100,6 @@ The `d2l-collapsible-panel` element is a container that provides specific layout
|
|
100
100
|
d2l-collapsible-panel {
|
101
101
|
width: 800px;
|
102
102
|
}
|
103
|
-
/* TODO: remove this when daylight demo resizing is fixed */
|
104
|
-
d2l-collapsible-panel:not([expanded]) {
|
105
|
-
margin-bottom: 14rem;
|
106
|
-
}
|
107
103
|
</style>
|
108
104
|
|
109
105
|
<d2l-collapsible-panel panel-title="Collapsible Panel">
|
@@ -238,10 +234,6 @@ class CollapsiblePanelDaylightDemo extends LitElement {
|
|
238
234
|
d2l-collapsible-panel {
|
239
235
|
width: 500px;
|
240
236
|
}
|
241
|
-
/* TODO: remove this when daylight demo resizing is fixed */
|
242
|
-
d2l-collapsible-panel:not([expanded]) {
|
243
|
-
margin-bottom: 12rem;
|
244
|
-
}
|
245
237
|
`];
|
246
238
|
}
|
247
239
|
|
@@ -216,7 +216,13 @@ class CollapsiblePanel extends SkeletonMixin(FocusMixin(RtlMixin(LitElement))) {
|
|
216
216
|
}
|
217
217
|
.d2l-collapsible-panel-opener {
|
218
218
|
align-self: self-start;
|
219
|
+
background-color: transparent;
|
220
|
+
border: none;
|
219
221
|
margin-inline-end: var(--d2l-collapsible-panel-spacing-inline);
|
222
|
+
order: 1;
|
223
|
+
outline: none;
|
224
|
+
padding-block: 0;
|
225
|
+
padding-inline: 0;
|
220
226
|
}
|
221
227
|
.d2l-collapsible-panel-opener > d2l-icon-custom {
|
222
228
|
height: 0.9rem;
|
@@ -307,7 +313,7 @@ class CollapsiblePanel extends SkeletonMixin(FocusMixin(RtlMixin(LitElement))) {
|
|
307
313
|
}
|
308
314
|
|
309
315
|
static get focusElementSelector() {
|
310
|
-
return '
|
316
|
+
return '.d2l-collapsible-panel-opener';
|
311
317
|
}
|
312
318
|
|
313
319
|
disconnectedCallback() {
|
@@ -324,17 +330,8 @@ class CollapsiblePanel extends SkeletonMixin(FocusMixin(RtlMixin(LitElement))) {
|
|
324
330
|
'scrolled': this._scrolled,
|
325
331
|
'no-bottom-border': this._noBottomBorder,
|
326
332
|
};
|
327
|
-
const expandCollapseLabel = this.expandCollapseLabel || this.panelTitle;
|
328
333
|
|
329
334
|
return html`
|
330
|
-
<button
|
331
|
-
aria-expanded="${this.expanded}"
|
332
|
-
class="d2l-offscreen"
|
333
|
-
type="button"
|
334
|
-
@click="${this._toggleExpand}"
|
335
|
-
@focus="${this._onFocus}"
|
336
|
-
@blur="${this._onBlur}"
|
337
|
-
>${expandCollapseLabel}</button>
|
338
335
|
<div class="${classMap(classes)}" @click="${this._handlePanelClick}">
|
339
336
|
<div class="d2l-collapsible-panel-top-sentinel"></div>
|
340
337
|
${this._renderHeader()}
|
@@ -427,22 +424,31 @@ class CollapsiblePanel extends SkeletonMixin(FocusMixin(RtlMixin(LitElement))) {
|
|
427
424
|
}
|
428
425
|
|
429
426
|
_renderHeader() {
|
427
|
+
const expandCollapseLabel = this.expandCollapseLabel || this.panelTitle;
|
430
428
|
return html`
|
431
429
|
<div class="d2l-collapsible-panel-header" @click="${this._handleHeaderClick}">
|
432
430
|
<div class="d2l-collapsible-panel-before">
|
433
431
|
<slot name="before" @slotchange="${this._handleBeforeSlotChange}"></slot>
|
434
432
|
</div>
|
435
433
|
<div class="d2l-collapsible-panel-header-primary">
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
434
|
+
<button
|
435
|
+
class="d2l-collapsible-panel-opener"
|
436
|
+
aria-expanded="${this.expanded}"
|
437
|
+
type="button"
|
438
|
+
@click="${this._handleHeaderClick}"
|
439
|
+
@focus="${this._onFocus}"
|
440
|
+
@blur="${this._onBlur}"
|
441
|
+
aria-label="${expandCollapseLabel}"
|
442
|
+
>
|
441
443
|
<d2l-icon-custom size="tier1" class="d2l-skeletize">
|
442
444
|
<svg xmlns="http://www.w3.org/2000/svg" width="10" height="18" fill="none" viewBox="0 0 10 18">
|
443
445
|
<path stroke="var(--d2l-color-tungsten)" stroke-linejoin="round" stroke-width="2" d="m9 9-8 8V1l8 8Z"/>
|
444
446
|
</svg>
|
445
447
|
</d2l-icon-custom>
|
448
|
+
</button>
|
449
|
+
${this._renderPanelTitle()}
|
450
|
+
<div class="d2l-collapsible-panel-header-actions" @click="${this._handleActionsClick}">
|
451
|
+
<slot name="actions"></slot>
|
446
452
|
</div>
|
447
453
|
</div>
|
448
454
|
<div class="d2l-collapsible-panel-header-secondary" @click="${this._handleHeaderSecondaryClick}">
|
@@ -8,6 +8,7 @@
|
|
8
8
|
<script type="module">
|
9
9
|
import '../../button/button-subtle.js';
|
10
10
|
import '../../demo/demo-page.js';
|
11
|
+
import '../../link/link.js';
|
11
12
|
import '../test/popover.js';
|
12
13
|
</script>
|
13
14
|
</head>
|
@@ -32,6 +33,24 @@
|
|
32
33
|
</template>
|
33
34
|
</d2l-demo-snippet>
|
34
35
|
|
36
|
+
<h2>Popover (trap-focus)</h2>
|
37
|
+
<d2l-demo-snippet>
|
38
|
+
<template>
|
39
|
+
<d2l-button-subtle id="open2" text="Open"></d2l-button-subtle>
|
40
|
+
<d2l-test-popover trap-focus id="popover2" style="max-width: 400px;">
|
41
|
+
<d2l-link href="https://pirateipsum.me/" target="_blank">Pirate Ipsum</d2l-link>
|
42
|
+
<div>Sink me piracy Gold Road quarterdeck wherry long boat line pillage walk the plank Plate Fleet. Haul wind black spot strike colors deadlights lee Barbary Coast yo-ho-ho ballast gally Shiver me timbers. Sea Legs quarterdeck yard scourge of the seven seas coffer plunder lanyard holystone code of conduct belay.</div>
|
43
|
+
<d2l-button-subtle id="close2" text="Close"></d2l-button-subtle>
|
44
|
+
</d2l-test-popover>
|
45
|
+
<script>
|
46
|
+
const popover2 = document.querySelector('#popover2');
|
47
|
+
document.querySelector('#open2').addEventListener('click', () => popover2.opened = !popover2.opened);
|
48
|
+
document.querySelector('#close2').addEventListener('click', () => popover2.opened = false);
|
49
|
+
popover2.addEventListener('d2l-popover-focus-enter', e => console.log(e.type, e));
|
50
|
+
</script>
|
51
|
+
</template>
|
52
|
+
</d2l-demo-snippet>
|
53
|
+
|
35
54
|
<script>
|
36
55
|
document.addEventListener('d2l-popover-open', e => console.log(e.type, e));
|
37
56
|
document.addEventListener('d2l-popover-close', e => console.log(e.type, e));
|
@@ -1,4 +1,5 @@
|
|
1
1
|
import '../colors/colors.js';
|
2
|
+
import '../focus-trap/focus-trap.js';
|
2
3
|
import { clearDismissible, setDismissible } from '../../helpers/dismissible.js';
|
3
4
|
import { css, html } from 'lit';
|
4
5
|
import { getComposedActiveElement, getFirstFocusableDescendant, getPreviousFocusableAncestor } from '../../helpers/focus.js';
|
@@ -16,6 +17,7 @@ export const PopoverMixin = superclass => class extends superclass {
|
|
16
17
|
_noAutoClose: { state: true },
|
17
18
|
_noAutoFocus: { state: true },
|
18
19
|
_opened: { type: Boolean, reflect: true, attribute: '_opened' },
|
20
|
+
_trapFocus: { state: true },
|
19
21
|
_useNativePopover: { type: String, reflect: true, attribute: 'popover' }
|
20
22
|
};
|
21
23
|
}
|
@@ -92,52 +94,43 @@ export const PopoverMixin = superclass => class extends superclass {
|
|
92
94
|
this._clearDismissible();
|
93
95
|
}
|
94
96
|
|
95
|
-
|
96
|
-
|
97
|
-
if (changedProperties.has('_opened')) {
|
97
|
+
async close() {
|
98
|
+
if (!this._opened) return;
|
98
99
|
|
99
|
-
|
100
|
-
if (this._opened) this.showPopover();
|
101
|
-
else this.hidePopover();
|
102
|
-
}
|
103
|
-
|
104
|
-
this._previousFocusableAncestor = this._opened ? getPreviousFocusableAncestor(this, false, false) : null;
|
105
|
-
|
106
|
-
if (this._opened) {
|
107
|
-
|
108
|
-
this._opener = getComposedActiveElement();
|
109
|
-
this._addAutoCloseHandlers();
|
110
|
-
this._dismissibleId = setDismissible(() => this.close());
|
111
|
-
this._focusContent(this);
|
112
|
-
this.dispatchEvent(new CustomEvent('d2l-popover-open', { bubbles: true, composed: true }));
|
113
|
-
|
114
|
-
} else if (changedProperties.get('_opened') !== undefined) {
|
115
|
-
|
116
|
-
this._removeAutoCloseHandlers();
|
117
|
-
this._clearDismissible();
|
118
|
-
this._focusOpener();
|
119
|
-
this.dispatchEvent(new CustomEvent('d2l-popover-close', { bubbles: true, composed: true }));
|
120
|
-
|
121
|
-
}
|
100
|
+
this._opened = false;
|
122
101
|
|
123
|
-
|
124
|
-
}
|
102
|
+
if (this._useNativePopover) this.hidePopover();
|
125
103
|
|
126
|
-
|
127
|
-
this.
|
128
|
-
|
104
|
+
this._previousFocusableAncestor = null;
|
105
|
+
this._removeAutoCloseHandlers();
|
106
|
+
this._clearDismissible();
|
107
|
+
await this.updateComplete; // wait before applying focus to opener
|
108
|
+
this._focusOpener();
|
109
|
+
this.dispatchEvent(new CustomEvent('d2l-popover-close', { bubbles: true, composed: true }));
|
129
110
|
}
|
130
111
|
|
131
112
|
configure(properties) {
|
132
113
|
this._noAutoClose = properties?.noAutoClose ?? false;
|
133
114
|
this._noAutoFocus = properties?.noAutoFocus ?? false;
|
134
|
-
this.
|
115
|
+
this._trapFocus = properties?.trapFocus ?? false;
|
135
116
|
}
|
136
117
|
|
137
|
-
open(applyFocus = true) {
|
118
|
+
async open(applyFocus = true) {
|
119
|
+
if (this._opened) return;
|
120
|
+
|
138
121
|
this._applyFocus = applyFocus !== undefined ? applyFocus : true;
|
139
122
|
this._opened = true;
|
140
|
-
|
123
|
+
|
124
|
+
await this.updateComplete; // wait for popover attribute before managing top-layer
|
125
|
+
if (this._useNativePopover) this.showPopover();
|
126
|
+
|
127
|
+
this._previousFocusableAncestor = getPreviousFocusableAncestor(this, false, false);
|
128
|
+
|
129
|
+
this._opener = getComposedActiveElement();
|
130
|
+
this._addAutoCloseHandlers();
|
131
|
+
this._dismissibleId = setDismissible(() => this.close());
|
132
|
+
this._focusContent(this);
|
133
|
+
this.dispatchEvent(new CustomEvent('d2l-popover-open', { bubbles: true, composed: true }));
|
141
134
|
}
|
142
135
|
|
143
136
|
toggleOpen(applyFocus = true) {
|
@@ -209,7 +202,7 @@ export const PopoverMixin = superclass => class extends superclass {
|
|
209
202
|
}
|
210
203
|
|
211
204
|
const activeElement = getComposedActiveElement();
|
212
|
-
if (isComposedAncestor(this
|
205
|
+
if (isComposedAncestor(this, activeElement)
|
213
206
|
|| activeElement === this._opener) {
|
214
207
|
return;
|
215
208
|
}
|
@@ -219,6 +212,13 @@ export const PopoverMixin = superclass => class extends superclass {
|
|
219
212
|
|
220
213
|
}
|
221
214
|
|
215
|
+
_handleFocusTrapEnter() {
|
216
|
+
this._focusContent(this._getContentContainer());
|
217
|
+
|
218
|
+
/** Dispatched when user focus enters the popover (trap-focus option only) */
|
219
|
+
this.dispatchEvent(new CustomEvent('d2l-popover-focus-enter', { detail: { applyFocus: this._applyFocus } }));
|
220
|
+
}
|
221
|
+
|
222
222
|
_removeAutoCloseHandlers() {
|
223
223
|
this.removeEventListener('blur', this._handleAutoCloseFocus, { capture: true });
|
224
224
|
document.body?.removeEventListener('focus', this._handleAutoCloseFocus, { capture: true }); // DE41322: document.body can be null in some scenarios
|
@@ -226,7 +226,13 @@ export const PopoverMixin = superclass => class extends superclass {
|
|
226
226
|
}
|
227
227
|
|
228
228
|
_renderPopover() {
|
229
|
-
|
229
|
+
const content = html`<div class="content"><slot></slot></div>`;
|
230
|
+
|
231
|
+
if (this._trapFocus) return html`<d2l-focus-trap @d2l-focus-trap-enter="${this._handleFocusTrapEnter}" ?trap="${this._opened}">
|
232
|
+
${content}
|
233
|
+
</d2l-focus-trap>`;
|
234
|
+
|
235
|
+
return content;
|
230
236
|
}
|
231
237
|
|
232
238
|
};
|
package/custom-elements.json
CHANGED
@@ -10734,6 +10734,12 @@
|
|
10734
10734
|
"description": "Whether the popover is open or not",
|
10735
10735
|
"type": "boolean",
|
10736
10736
|
"default": "false"
|
10737
|
+
},
|
10738
|
+
{
|
10739
|
+
"name": "trap-focus",
|
10740
|
+
"description": "Whether to render a d2l-focus-trap around the content",
|
10741
|
+
"type": "boolean",
|
10742
|
+
"default": "false"
|
10737
10743
|
}
|
10738
10744
|
],
|
10739
10745
|
"properties": [
|
@@ -10757,14 +10763,25 @@
|
|
10757
10763
|
"description": "Whether the popover is open or not",
|
10758
10764
|
"type": "boolean",
|
10759
10765
|
"default": "false"
|
10766
|
+
},
|
10767
|
+
{
|
10768
|
+
"name": "trapFocus",
|
10769
|
+
"attribute": "trap-focus",
|
10770
|
+
"description": "Whether to render a d2l-focus-trap around the content",
|
10771
|
+
"type": "boolean",
|
10772
|
+
"default": "false"
|
10760
10773
|
}
|
10761
10774
|
],
|
10762
10775
|
"events": [
|
10776
|
+
{
|
10777
|
+
"name": "d2l-popover-close"
|
10778
|
+
},
|
10763
10779
|
{
|
10764
10780
|
"name": "d2l-popover-open"
|
10765
10781
|
},
|
10766
10782
|
{
|
10767
|
-
"name": "d2l-popover-
|
10783
|
+
"name": "d2l-popover-focus-enter",
|
10784
|
+
"description": "Dispatched when user focus enters the popover (trap-focus option only)"
|
10768
10785
|
}
|
10769
10786
|
]
|
10770
10787
|
},
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@brightspace-ui/core",
|
3
|
-
"version": "3.25.
|
3
|
+
"version": "3.25.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",
|