@momentum-design/components 0.133.24 → 0.133.26
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/dist/browser/index.js +247 -247
- package/dist/browser/index.js.map +3 -3
- package/dist/components/searchpopover/searchpopover.component.d.ts +7 -0
- package/dist/components/searchpopover/searchpopover.component.js +13 -1
- package/dist/custom-elements.json +6 -0
- package/dist/utils/dom.d.ts +6 -0
- package/dist/utils/dom.js +10 -1
- package/dist/utils/mixins/focus/FocusTrapMixin.js +1 -1
- package/package.json +1 -1
|
@@ -111,6 +111,13 @@ declare class Searchpopover extends Searchfield {
|
|
|
111
111
|
* @internal
|
|
112
112
|
*/
|
|
113
113
|
protected get scrollContainer(): HTMLElement | null;
|
|
114
|
+
/**
|
|
115
|
+
* Handles the popover hidden event by focusing the input element.
|
|
116
|
+
* This replaces `focus-back-to-trigger` since the trigger is a non-focusable div.
|
|
117
|
+
* Only moves focus to the input if focus is currently within the searchpopover component.
|
|
118
|
+
* If focus is outside the component, it is left unchanged.
|
|
119
|
+
*/
|
|
120
|
+
private handlePopoverHidden;
|
|
114
121
|
protected renderInputElement(): import("lit-html").TemplateResult<1>;
|
|
115
122
|
render(): import("lit-html").TemplateResult<1>;
|
|
116
123
|
static styles: Array<CSSResult>;
|
|
@@ -129,6 +129,18 @@ class Searchpopover extends Searchfield {
|
|
|
129
129
|
var _a, _b;
|
|
130
130
|
return (_b = (_a = this.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelector('[part="filters-container"]')) !== null && _b !== void 0 ? _b : null;
|
|
131
131
|
}
|
|
132
|
+
/**
|
|
133
|
+
* Handles the popover hidden event by focusing the input element.
|
|
134
|
+
* This replaces `focus-back-to-trigger` since the trigger is a non-focusable div.
|
|
135
|
+
* Only moves focus to the input if focus is currently within the searchpopover component.
|
|
136
|
+
* If focus is outside the component, it is left unchanged.
|
|
137
|
+
*/
|
|
138
|
+
handlePopoverHidden() {
|
|
139
|
+
var _a;
|
|
140
|
+
if (this === document.activeElement || this.contains(document.activeElement)) {
|
|
141
|
+
(_a = this.inputElement) === null || _a === void 0 ? void 0 : _a.focus();
|
|
142
|
+
}
|
|
143
|
+
}
|
|
132
144
|
renderInputElement() {
|
|
133
145
|
var _a, _b;
|
|
134
146
|
const placeholderText = this.hasChips ? '' : this.placeholder;
|
|
@@ -188,8 +200,8 @@ class Searchpopover extends Searchfield {
|
|
|
188
200
|
?visible=${this.displayPopover}
|
|
189
201
|
hide-on-outside-click
|
|
190
202
|
hide-on-escape
|
|
191
|
-
focus-back-to-trigger
|
|
192
203
|
size
|
|
204
|
+
@hidden=${this.handlePopoverHidden}
|
|
193
205
|
placement="${this.placement}"
|
|
194
206
|
aria-label="${ifDefined(this.popoverAriaLabel)}"
|
|
195
207
|
disable-aria-expanded
|
|
@@ -40425,6 +40425,12 @@
|
|
|
40425
40425
|
"module": "components/input/input.component.js"
|
|
40426
40426
|
}
|
|
40427
40427
|
},
|
|
40428
|
+
{
|
|
40429
|
+
"kind": "method",
|
|
40430
|
+
"name": "handlePopoverHidden",
|
|
40431
|
+
"privacy": "private",
|
|
40432
|
+
"description": "Handles the popover hidden event by focusing the input element.\nThis replaces `focus-back-to-trigger` since the trigger is a non-focusable div.\nOnly moves focus to the input if focus is currently within the searchpopover component.\nIf focus is outside the component, it is left unchanged."
|
|
40433
|
+
},
|
|
40428
40434
|
{
|
|
40429
40435
|
"kind": "field",
|
|
40430
40436
|
"name": "helpText",
|
package/dist/utils/dom.d.ts
CHANGED
|
@@ -7,6 +7,12 @@ type FindFocusableOptions = {
|
|
|
7
7
|
excludedElements?: HTMLElement[];
|
|
8
8
|
/** Selectors to include in the search. */
|
|
9
9
|
includeSelectors?: string[];
|
|
10
|
+
/**
|
|
11
|
+
* When true, elements with `tabindex="-1"` and their subtrees are excluded from the search.
|
|
12
|
+
* This supports composite widget patterns (e.g., roving tabindex in lists) where
|
|
13
|
+
* inactive items and their children should not be reachable via Tab navigation.
|
|
14
|
+
*/
|
|
15
|
+
stopAtNonTabbable?: boolean;
|
|
10
16
|
};
|
|
11
17
|
/**
|
|
12
18
|
* nodeB precedes nodeA in either a pre-order depth-first traversal of a tree containing both
|
package/dist/utils/dom.js
CHANGED
|
@@ -166,17 +166,21 @@ export const isFocusable = (element) => !isDisabled(element) && isTabbable(eleme
|
|
|
166
166
|
* @returns The list of focusable elements.
|
|
167
167
|
*/
|
|
168
168
|
export const findFocusable = (root, options = {}) => {
|
|
169
|
-
var _a, _b;
|
|
169
|
+
var _a, _b, _c;
|
|
170
170
|
if (!root) {
|
|
171
171
|
return [];
|
|
172
172
|
}
|
|
173
173
|
const excludesSet = new Set((_a = options === null || options === void 0 ? void 0 : options.excludedElements) !== null && _a !== void 0 ? _a : []);
|
|
174
174
|
const includeSelectors = (_b = options === null || options === void 0 ? void 0 : options.includeSelectors) !== null && _b !== void 0 ? _b : [];
|
|
175
|
+
const stopAtNonTabbable = (_c = options === null || options === void 0 ? void 0 : options.stopAtNonTabbable) !== null && _c !== void 0 ? _c : false;
|
|
175
176
|
const matches = new Set();
|
|
176
177
|
const focusableCheck = (element) => {
|
|
177
178
|
if (!(element instanceof HTMLSlotElement) && (isHidden(element) || isDisabled(element))) {
|
|
178
179
|
return 'stop';
|
|
179
180
|
}
|
|
181
|
+
if (stopAtNonTabbable && !(element instanceof HTMLSlotElement) && element.getAttribute('tabindex') === '-1') {
|
|
182
|
+
return 'stop';
|
|
183
|
+
}
|
|
180
184
|
return isMatchAny(element, includeSelectors) || (isTabbable(element) && isInteractiveElement(element))
|
|
181
185
|
? 'focusable'
|
|
182
186
|
: 'continue';
|
|
@@ -211,6 +215,11 @@ export const findFocusable = (root, options = {}) => {
|
|
|
211
215
|
const assignedNodes = element.assignedElements({ flatten: true });
|
|
212
216
|
assignedNodes.forEach(node => {
|
|
213
217
|
if (node instanceof HTMLElement) {
|
|
218
|
+
// When stopAtNonTabbable is enabled, skip non-tabbable slotted elements and their
|
|
219
|
+
// subtrees to support composite widget patterns (e.g., roving tabindex in lists)
|
|
220
|
+
if (stopAtNonTabbable && !(node instanceof HTMLSlotElement) && node.getAttribute('tabindex') === '-1') {
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
214
223
|
finder(node);
|
|
215
224
|
}
|
|
216
225
|
});
|
|
@@ -55,7 +55,7 @@ export const FocusTrapMixin = (superClass) => {
|
|
|
55
55
|
setFocusableElements() {
|
|
56
56
|
if (!this.shadowRoot)
|
|
57
57
|
return;
|
|
58
|
-
this.focusableElements = findFocusable(this.shadowRoot);
|
|
58
|
+
this.focusableElements = findFocusable(this.shadowRoot, { stopAtNonTabbable: true });
|
|
59
59
|
}
|
|
60
60
|
/**
|
|
61
61
|
* Sets the initial focus within the container.
|