@brightspace-ui/core 3.24.1 → 3.25.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.
@@ -51,7 +51,8 @@ class InputDateTimeRangeTo extends SkeletonMixin(LocalizeCoreElement(LitElement)
|
|
51
51
|
display: flex;
|
52
52
|
flex-wrap: wrap;
|
53
53
|
}
|
54
|
-
:host([display-to]) div:not(.d2l-input-date-time-range-to-container-block).d2l-input-date-time-range-to-container
|
54
|
+
:host([display-to]) div:not(.d2l-input-date-time-range-to-container-block).d2l-input-date-time-range-to-container,
|
55
|
+
:host([display-to]) div:not(.d2l-input-date-time-range-to-container-block).d2l-input-date-time-range-to-container .d2l-input-date-time-range-end-container {
|
55
56
|
column-gap: 0.9rem;
|
56
57
|
}
|
57
58
|
.d2l-input-date-time-range-end-container {
|
@@ -114,10 +115,10 @@ class InputDateTimeRangeTo extends SkeletonMixin(LocalizeCoreElement(LitElement)
|
|
114
115
|
<div class="d2l-input-date-time-range-start-container">
|
115
116
|
<slot name="left"></slot>
|
116
117
|
</div>
|
118
|
+
<div class="d2l-input-date-time-range-end-container">
|
117
119
|
<div class="d2l-body-small d2l-skeletize d2l-input-date-time-range-to-to">
|
118
120
|
${this.localize('components.input-date-time-range-to.to')}
|
119
121
|
</div>
|
120
|
-
<div class="d2l-input-date-time-range-end-container">
|
121
122
|
<slot name="right"></slot>
|
122
123
|
</div>
|
123
124
|
</div>
|
@@ -1,7 +1,7 @@
|
|
1
1
|
import '../colors/colors.js';
|
2
2
|
import { clearDismissible, setDismissible } from '../../helpers/dismissible.js';
|
3
3
|
import { css, html } from 'lit';
|
4
|
-
import { getComposedActiveElement, getPreviousFocusableAncestor } from '../../helpers/focus.js';
|
4
|
+
import { getComposedActiveElement, getFirstFocusableDescendant, getPreviousFocusableAncestor } from '../../helpers/focus.js';
|
5
5
|
import { isComposedAncestor } from '../../helpers/dom.js';
|
6
6
|
|
7
7
|
const isSupported = ('popover' in HTMLElement.prototype);
|
@@ -13,16 +13,9 @@ export const PopoverMixin = superclass => class extends superclass {
|
|
13
13
|
|
14
14
|
static get properties() {
|
15
15
|
return {
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
*/
|
20
|
-
opened: { type: Boolean, reflect: true },
|
21
|
-
/**
|
22
|
-
* Whether to disable auto-close/light-dismiss
|
23
|
-
* @type {boolean}
|
24
|
-
*/
|
25
|
-
noAutoClose: { type: Boolean, reflect: true, attribute: 'no-auto-close' },
|
16
|
+
_noAutoClose: { state: true },
|
17
|
+
_noAutoFocus: { state: true },
|
18
|
+
_opened: { type: Boolean, reflect: true, attribute: '_opened' },
|
26
19
|
_useNativePopover: { type: String, reflect: true, attribute: 'popover' }
|
27
20
|
};
|
28
21
|
}
|
@@ -55,7 +48,7 @@ export const PopoverMixin = superclass => class extends superclass {
|
|
55
48
|
:host(:not([popover])) {
|
56
49
|
z-index: 998; /* position on top of floating buttons */
|
57
50
|
}
|
58
|
-
:host([
|
51
|
+
:host([_opened]) {
|
59
52
|
display: inline-block;
|
60
53
|
}
|
61
54
|
|
@@ -65,6 +58,7 @@ export const PopoverMixin = superclass => class extends superclass {
|
|
65
58
|
border-radius: var(--d2l-popover-border-radius, var(--d2l-popover-default-border-radius));
|
66
59
|
box-shadow: var(--d2l-popover-shadow, var(--d2l-popover-default-shadow));
|
67
60
|
box-sizing: border-box;
|
61
|
+
outline: none;
|
68
62
|
}
|
69
63
|
|
70
64
|
@keyframes d2l-popover-animation {
|
@@ -72,8 +66,8 @@ export const PopoverMixin = superclass => class extends superclass {
|
|
72
66
|
100% { opacity: 1; transform: translate(0, 0); }
|
73
67
|
}
|
74
68
|
@media (prefers-reduced-motion: no-preference) {
|
75
|
-
:host([
|
76
|
-
animation: var(--d2l-popover-animation-name, var(--d2l-popover-default-animation-name))
|
69
|
+
:host([_opened]) {
|
70
|
+
animation: var(--d2l-popover-animation-name, var(--d2l-popover-default-animation-name)) 300ms ease;
|
77
71
|
}
|
78
72
|
}
|
79
73
|
`;
|
@@ -81,8 +75,7 @@ export const PopoverMixin = superclass => class extends superclass {
|
|
81
75
|
|
82
76
|
constructor() {
|
83
77
|
super();
|
84
|
-
this.
|
85
|
-
this.opened = false;
|
78
|
+
this.configure();
|
86
79
|
this._useNativePopover = isSupported ? 'manual' : undefined;
|
87
80
|
this._handleAutoCloseClick = this._handleAutoCloseClick.bind(this);
|
88
81
|
this._handleAutoCloseFocus = this._handleAutoCloseFocus.bind(this);
|
@@ -90,7 +83,7 @@ export const PopoverMixin = superclass => class extends superclass {
|
|
90
83
|
|
91
84
|
connectedCallback() {
|
92
85
|
super.connectedCallback();
|
93
|
-
if (this.
|
86
|
+
if (this._opened) this._addAutoCloseHandlers();
|
94
87
|
}
|
95
88
|
|
96
89
|
disconnectedCallback() {
|
@@ -101,29 +94,57 @@ export const PopoverMixin = superclass => class extends superclass {
|
|
101
94
|
|
102
95
|
updated(changedProperties) {
|
103
96
|
super.updated(changedProperties);
|
104
|
-
if (changedProperties.has('
|
97
|
+
if (changedProperties.has('_opened')) {
|
105
98
|
|
106
99
|
if (this._useNativePopover) {
|
107
|
-
if (this.
|
100
|
+
if (this._opened) this.showPopover();
|
108
101
|
else this.hidePopover();
|
109
102
|
}
|
110
103
|
|
111
|
-
this._previousFocusableAncestor = this.
|
104
|
+
this._previousFocusableAncestor = this._opened ? getPreviousFocusableAncestor(this, false, false) : null;
|
105
|
+
|
106
|
+
if (this._opened) {
|
112
107
|
|
113
|
-
if (this.opened) {
|
114
108
|
this._opener = getComposedActiveElement();
|
115
109
|
this._addAutoCloseHandlers();
|
116
|
-
this._dismissibleId = setDismissible(() => this.
|
110
|
+
this._dismissibleId = setDismissible(() => this.close());
|
111
|
+
this._focusContent(this);
|
117
112
|
this.dispatchEvent(new CustomEvent('d2l-popover-open', { bubbles: true, composed: true }));
|
118
|
-
|
113
|
+
|
114
|
+
} else if (changedProperties.get('_opened') !== undefined) {
|
115
|
+
|
119
116
|
this._removeAutoCloseHandlers();
|
120
117
|
this._clearDismissible();
|
118
|
+
this._focusOpener();
|
121
119
|
this.dispatchEvent(new CustomEvent('d2l-popover-close', { bubbles: true, composed: true }));
|
120
|
+
|
122
121
|
}
|
123
122
|
|
124
123
|
}
|
125
124
|
}
|
126
125
|
|
126
|
+
close() {
|
127
|
+
this._opened = false;
|
128
|
+
return this.updateComplete;
|
129
|
+
}
|
130
|
+
|
131
|
+
configure(properties) {
|
132
|
+
this._noAutoClose = properties?.noAutoClose ?? false;
|
133
|
+
this._noAutoFocus = properties?.noAutoFocus ?? false;
|
134
|
+
this._opened = properties?.opened ?? false;
|
135
|
+
}
|
136
|
+
|
137
|
+
open(applyFocus = true) {
|
138
|
+
this._applyFocus = applyFocus !== undefined ? applyFocus : true;
|
139
|
+
this._opened = true;
|
140
|
+
return this.updateComplete;
|
141
|
+
}
|
142
|
+
|
143
|
+
toggleOpen(applyFocus = true) {
|
144
|
+
if (this._opened) return this.close();
|
145
|
+
else return this.open(!this._noAutoFocus && applyFocus);
|
146
|
+
}
|
147
|
+
|
127
148
|
_addAutoCloseHandlers() {
|
128
149
|
this.addEventListener('blur', this._handleAutoCloseFocus, { capture: true });
|
129
150
|
document.body.addEventListener('focus', this._handleAutoCloseFocus, { capture: true });
|
@@ -136,25 +157,42 @@ export const PopoverMixin = superclass => class extends superclass {
|
|
136
157
|
this._dismissibleId = null;
|
137
158
|
}
|
138
159
|
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
160
|
+
_focusContent(container) {
|
161
|
+
if (this._noAutoFocus || this._applyFocus === false) return;
|
162
|
+
|
163
|
+
const focusable = getFirstFocusableDescendant(container);
|
164
|
+
if (focusable) {
|
165
|
+
// Removing the rAF call can allow infinite focus looping to happen in content using a focus trap
|
166
|
+
requestAnimationFrame(() => focusable.focus());
|
167
|
+
} else {
|
168
|
+
const content = this._getContentContainer();
|
169
|
+
content.setAttribute('tabindex', '-1');
|
170
|
+
content.focus();
|
171
|
+
}
|
172
|
+
}
|
173
|
+
|
174
|
+
_focusOpener() {
|
175
|
+
if (!document.activeElement) return;
|
176
|
+
if (!isComposedAncestor(this, getComposedActiveElement())) return;
|
177
|
+
|
178
|
+
this?._opener.focus();
|
179
|
+
}
|
143
180
|
|
144
|
-
|
181
|
+
_getContentContainer() {
|
182
|
+
return this.shadowRoot.querySelector('.content');
|
145
183
|
}
|
146
184
|
|
147
185
|
_handleAutoCloseClick(e) {
|
148
186
|
|
149
|
-
if (!this.
|
187
|
+
if (!this._opened || this._noAutoClose) return;
|
150
188
|
|
151
189
|
const rootTarget = e.composedPath()[0];
|
152
|
-
if (isComposedAncestor(this.
|
190
|
+
if (isComposedAncestor(this._getContentContainer(), rootTarget)
|
153
191
|
|| (this._opener !== document.body && isComposedAncestor(this._opener, rootTarget))) {
|
154
192
|
return;
|
155
193
|
}
|
156
194
|
|
157
|
-
this.
|
195
|
+
this.close();
|
158
196
|
}
|
159
197
|
|
160
198
|
_handleAutoCloseFocus() {
|
@@ -162,8 +200,8 @@ export const PopoverMixin = superclass => class extends superclass {
|
|
162
200
|
// todo: try to use relatedTarget instead - this logic is largely copied as-is from dropdown simply to mitigate risk of this fragile code
|
163
201
|
setTimeout(() => {
|
164
202
|
// we ignore focusable ancestors othrwise the popover will close when user clicks empty space inside the popover
|
165
|
-
if (!this.
|
166
|
-
|| this.
|
203
|
+
if (!this._opened
|
204
|
+
|| this._noAutoClose
|
167
205
|
|| !document.activeElement
|
168
206
|
|| document.activeElement === this._previousFocusableAncestor
|
169
207
|
|| document.activeElement === document.body) {
|
@@ -171,12 +209,12 @@ export const PopoverMixin = superclass => class extends superclass {
|
|
171
209
|
}
|
172
210
|
|
173
211
|
const activeElement = getComposedActiveElement();
|
174
|
-
if (isComposedAncestor(this.
|
212
|
+
if (isComposedAncestor(this._getContentContainer(), activeElement)
|
175
213
|
|| activeElement === this._opener) {
|
176
214
|
return;
|
177
215
|
}
|
178
216
|
|
179
|
-
this.
|
217
|
+
this.close();
|
180
218
|
}, 0);
|
181
219
|
|
182
220
|
}
|
package/custom-elements.json
CHANGED
@@ -10723,6 +10723,12 @@
|
|
10723
10723
|
"type": "boolean",
|
10724
10724
|
"default": "false"
|
10725
10725
|
},
|
10726
|
+
{
|
10727
|
+
"name": "no-auto-focus",
|
10728
|
+
"description": "Whether to disable auto-focus on the first focusable element when opened",
|
10729
|
+
"type": "boolean",
|
10730
|
+
"default": "false"
|
10731
|
+
},
|
10726
10732
|
{
|
10727
10733
|
"name": "opened",
|
10728
10734
|
"description": "Whether the popover is open or not",
|
@@ -10738,6 +10744,13 @@
|
|
10738
10744
|
"type": "boolean",
|
10739
10745
|
"default": "false"
|
10740
10746
|
},
|
10747
|
+
{
|
10748
|
+
"name": "noAutoFocus",
|
10749
|
+
"attribute": "no-auto-focus",
|
10750
|
+
"description": "Whether to disable auto-focus on the first focusable element when opened",
|
10751
|
+
"type": "boolean",
|
10752
|
+
"default": "false"
|
10753
|
+
},
|
10741
10754
|
{
|
10742
10755
|
"name": "opened",
|
10743
10756
|
"attribute": "opened",
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@brightspace-ui/core",
|
3
|
-
"version": "3.
|
3
|
+
"version": "3.25.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",
|