@brightspace-ui/core 3.24.0 → 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.
@@ -49,9 +49,6 @@ export const dropdownContentStyles = css`
|
|
49
49
|
bottom: calc(100% + var(--d2l-dropdown-verticaloffset, 16px));
|
50
50
|
top: auto;
|
51
51
|
}
|
52
|
-
:host([_fixed-positioning][opened-above]) {
|
53
|
-
bottom: 0;
|
54
|
-
}
|
55
52
|
|
56
53
|
:host([data-mobile][opened]:not([mobile-tray])) {
|
57
54
|
animation: var(--d2l-dropdown-animation-name) 300ms ease;
|
@@ -64,6 +61,11 @@ export const dropdownContentStyles = css`
|
|
64
61
|
top: auto;
|
65
62
|
}
|
66
63
|
|
64
|
+
:host([_fixed-positioning][opened-above]),
|
65
|
+
:host([_fixed-positioning][data-mobile][opened-above]:not([mobile-tray])) {
|
66
|
+
bottom: 0;
|
67
|
+
}
|
68
|
+
|
67
69
|
.d2l-dropdown-content-pointer {
|
68
70
|
clip: rect(-5px, 21px, 8px, -7px);
|
69
71
|
display: inline-block;
|
@@ -301,7 +301,7 @@ The `getUTCDateTimeRange(rangeType, diff)` helper function can be used to get th
|
|
301
301
|
|
302
302
|
This component is built to be used alongside the [d2l-filter-dimension-set](#d2l-filter-dimension-set) component. It will give you a selectable filter value which expands to allow the user to select a date range using either the `d2l-input-date-time-range` or `d2l-input-date-range` component (depending on the `type` of the component). Selection triggers the `d2l-filter-change` event, with `start-value` and `end-value` (in UTC) being included in the changes for the `selected` item.
|
303
303
|
|
304
|
-
<!-- docs: demo code properties name:d2l-filter-dimension-set-date-time-range-value align:start autoOpen:true autoSize:false size:
|
304
|
+
<!-- docs: demo code properties name:d2l-filter-dimension-set-date-time-range-value align:start autoOpen:true autoSize:false size:xlarge -->
|
305
305
|
```html
|
306
306
|
<script type="module">
|
307
307
|
import '@brightspace-ui/core/components/filter/filter.js';
|
@@ -311,9 +311,12 @@ This component is built to be used alongside the [d2l-filter-dimension-set](#d2l
|
|
311
311
|
</script>
|
312
312
|
<d2l-filter>
|
313
313
|
<d2l-filter-dimension-set key="dates" text="Dates">
|
314
|
-
<d2l-filter-dimension-set-
|
315
|
-
<d2l-filter-dimension-set-date-text-value key="
|
316
|
-
<d2l-filter-dimension-set-date-
|
314
|
+
<d2l-filter-dimension-set-value key="60days" text="Last 60 days"></d2l-filter-dimension-set-value>
|
315
|
+
<d2l-filter-dimension-set-date-text-value key="lastHour" range="lastHour"></d2l-filter-dimension-set-date-text-value>
|
316
|
+
<d2l-filter-dimension-set-date-text-value key="48hours" range="48hours" disabled></d2l-filter-dimension-set-date-text-value>
|
317
|
+
<d2l-filter-dimension-set-date-text-value key="today" range="today"></d2l-filter-dimension-set-date-text-value>
|
318
|
+
<d2l-filter-dimension-set-date-text-value key="6months" range="6months"></d2l-filter-dimension-set-date-text-value>
|
319
|
+
<d2l-filter-dimension-set-date-time-range-value key="custom" type="date"></d2l-filter-dimension-set-date-time-range-value>
|
317
320
|
</d2l-filter-dimension-set>
|
318
321
|
</d2l-filter>
|
319
322
|
```
|
@@ -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
|
}
|
@@ -30,6 +23,7 @@ export const PopoverMixin = superclass => class extends superclass {
|
|
30
23
|
static get styles() {
|
31
24
|
return css`
|
32
25
|
:host {
|
26
|
+
--d2l-popover-default-animation-name: d2l-popover-animation;
|
33
27
|
--d2l-popover-default-background-color: #ffffff;
|
34
28
|
--d2l-popover-default-border-color: var(--d2l-color-mica);
|
35
29
|
--d2l-popover-default-border-radius: 0.3rem;
|
@@ -54,7 +48,7 @@ export const PopoverMixin = superclass => class extends superclass {
|
|
54
48
|
:host(:not([popover])) {
|
55
49
|
z-index: 998; /* position on top of floating buttons */
|
56
50
|
}
|
57
|
-
:host([
|
51
|
+
:host([_opened]) {
|
58
52
|
display: inline-block;
|
59
53
|
}
|
60
54
|
|
@@ -64,14 +58,24 @@ export const PopoverMixin = superclass => class extends superclass {
|
|
64
58
|
border-radius: var(--d2l-popover-border-radius, var(--d2l-popover-default-border-radius));
|
65
59
|
box-shadow: var(--d2l-popover-shadow, var(--d2l-popover-default-shadow));
|
66
60
|
box-sizing: border-box;
|
61
|
+
outline: none;
|
62
|
+
}
|
63
|
+
|
64
|
+
@keyframes d2l-popover-animation {
|
65
|
+
0% { opacity: 0; transform: translate(0, -10px); }
|
66
|
+
100% { opacity: 1; transform: translate(0, 0); }
|
67
|
+
}
|
68
|
+
@media (prefers-reduced-motion: no-preference) {
|
69
|
+
:host([_opened]) {
|
70
|
+
animation: var(--d2l-popover-animation-name, var(--d2l-popover-default-animation-name)) 300ms ease;
|
71
|
+
}
|
67
72
|
}
|
68
73
|
`;
|
69
74
|
}
|
70
75
|
|
71
76
|
constructor() {
|
72
77
|
super();
|
73
|
-
this.
|
74
|
-
this.opened = false;
|
78
|
+
this.configure();
|
75
79
|
this._useNativePopover = isSupported ? 'manual' : undefined;
|
76
80
|
this._handleAutoCloseClick = this._handleAutoCloseClick.bind(this);
|
77
81
|
this._handleAutoCloseFocus = this._handleAutoCloseFocus.bind(this);
|
@@ -79,7 +83,7 @@ export const PopoverMixin = superclass => class extends superclass {
|
|
79
83
|
|
80
84
|
connectedCallback() {
|
81
85
|
super.connectedCallback();
|
82
|
-
if (this.
|
86
|
+
if (this._opened) this._addAutoCloseHandlers();
|
83
87
|
}
|
84
88
|
|
85
89
|
disconnectedCallback() {
|
@@ -90,29 +94,57 @@ export const PopoverMixin = superclass => class extends superclass {
|
|
90
94
|
|
91
95
|
updated(changedProperties) {
|
92
96
|
super.updated(changedProperties);
|
93
|
-
if (changedProperties.has('
|
97
|
+
if (changedProperties.has('_opened')) {
|
94
98
|
|
95
99
|
if (this._useNativePopover) {
|
96
|
-
if (this.
|
100
|
+
if (this._opened) this.showPopover();
|
97
101
|
else this.hidePopover();
|
98
102
|
}
|
99
103
|
|
100
|
-
this._previousFocusableAncestor = this.
|
104
|
+
this._previousFocusableAncestor = this._opened ? getPreviousFocusableAncestor(this, false, false) : null;
|
105
|
+
|
106
|
+
if (this._opened) {
|
101
107
|
|
102
|
-
if (this.opened) {
|
103
108
|
this._opener = getComposedActiveElement();
|
104
109
|
this._addAutoCloseHandlers();
|
105
|
-
this._dismissibleId = setDismissible(() => this.
|
110
|
+
this._dismissibleId = setDismissible(() => this.close());
|
111
|
+
this._focusContent(this);
|
106
112
|
this.dispatchEvent(new CustomEvent('d2l-popover-open', { bubbles: true, composed: true }));
|
107
|
-
|
113
|
+
|
114
|
+
} else if (changedProperties.get('_opened') !== undefined) {
|
115
|
+
|
108
116
|
this._removeAutoCloseHandlers();
|
109
117
|
this._clearDismissible();
|
118
|
+
this._focusOpener();
|
110
119
|
this.dispatchEvent(new CustomEvent('d2l-popover-close', { bubbles: true, composed: true }));
|
120
|
+
|
111
121
|
}
|
112
122
|
|
113
123
|
}
|
114
124
|
}
|
115
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
|
+
|
116
148
|
_addAutoCloseHandlers() {
|
117
149
|
this.addEventListener('blur', this._handleAutoCloseFocus, { capture: true });
|
118
150
|
document.body.addEventListener('focus', this._handleAutoCloseFocus, { capture: true });
|
@@ -125,25 +157,42 @@ export const PopoverMixin = superclass => class extends superclass {
|
|
125
157
|
this._dismissibleId = null;
|
126
158
|
}
|
127
159
|
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
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
|
+
}
|
132
180
|
|
133
|
-
|
181
|
+
_getContentContainer() {
|
182
|
+
return this.shadowRoot.querySelector('.content');
|
134
183
|
}
|
135
184
|
|
136
185
|
_handleAutoCloseClick(e) {
|
137
186
|
|
138
|
-
if (!this.
|
187
|
+
if (!this._opened || this._noAutoClose) return;
|
139
188
|
|
140
189
|
const rootTarget = e.composedPath()[0];
|
141
|
-
if (isComposedAncestor(this.
|
190
|
+
if (isComposedAncestor(this._getContentContainer(), rootTarget)
|
142
191
|
|| (this._opener !== document.body && isComposedAncestor(this._opener, rootTarget))) {
|
143
192
|
return;
|
144
193
|
}
|
145
194
|
|
146
|
-
this.
|
195
|
+
this.close();
|
147
196
|
}
|
148
197
|
|
149
198
|
_handleAutoCloseFocus() {
|
@@ -151,8 +200,8 @@ export const PopoverMixin = superclass => class extends superclass {
|
|
151
200
|
// todo: try to use relatedTarget instead - this logic is largely copied as-is from dropdown simply to mitigate risk of this fragile code
|
152
201
|
setTimeout(() => {
|
153
202
|
// we ignore focusable ancestors othrwise the popover will close when user clicks empty space inside the popover
|
154
|
-
if (!this.
|
155
|
-
|| this.
|
203
|
+
if (!this._opened
|
204
|
+
|| this._noAutoClose
|
156
205
|
|| !document.activeElement
|
157
206
|
|| document.activeElement === this._previousFocusableAncestor
|
158
207
|
|| document.activeElement === document.body) {
|
@@ -160,12 +209,12 @@ export const PopoverMixin = superclass => class extends superclass {
|
|
160
209
|
}
|
161
210
|
|
162
211
|
const activeElement = getComposedActiveElement();
|
163
|
-
if (isComposedAncestor(this.
|
212
|
+
if (isComposedAncestor(this._getContentContainer(), activeElement)
|
164
213
|
|| activeElement === this._opener) {
|
165
214
|
return;
|
166
215
|
}
|
167
216
|
|
168
|
-
this.
|
217
|
+
this.close();
|
169
218
|
}, 0);
|
170
219
|
|
171
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",
|