Skip to content
This repository has been archived by the owner on Mar 8, 2023. It is now read-only.

fix(modal): include select shadow root children in focus wrap queries #689

Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions src/components/modal/modal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ const PRECEDING = Node.DOCUMENT_POSITION_PRECEDING | Node.DOCUMENT_POSITION_CONT
const FOLLOWING = Node.DOCUMENT_POSITION_FOLLOWING | Node.DOCUMENT_POSITION_CONTAINED_BY;

/**
* Tries to focus on the given elements and bails out if one of the is successful.
* Tries to focus on the given elements and bails out if one of them is successful.
* @param elems The elements.
* @param reverse `true` to go through the list in reverse order.
* @returns `true` if one of the attempts is successful, `false` otherwise.
Expand Down Expand Up @@ -99,14 +99,17 @@ class BXModal extends HostListenerMixin(LitElement) {
@HostListener('shadowRoot:focusout')
// @ts-ignore: The decorator refers to this method but TS thinks this method is not referred to
private _handleBlur = async ({ target, relatedTarget }: FocusEvent) => {
const { open, _startSentinelNode: startSentinelNode, _endSentinelNode: endSentinelNode } = this;
const oldContains = target !== this && this.contains(target as Node);
const currentContains = relatedTarget !== this && this.contains(relatedTarget as Node);
const currentContains =
relatedTarget !== this &&
(this.contains(relatedTarget as Node) ||
(this.shadowRoot?.contains(relatedTarget as Node) && relatedTarget !== (endSentinelNode as Node)));

// Performs focus wrapping if _all_ of the following is met:
// * This modal is open
// * The viewport still has focus
// * Modal body used to have focus but no longer has focus
const { open, _startSentinelNode: startSentinelNode, _endSentinelNode: endSentinelNode } = this;
const { selectorTabbable: selectorTabbableForModal } = this.constructor as typeof BXModal;
if (open && relatedTarget && oldContains && !currentContains) {
const comparisonResult = (target as Node).compareDocumentPosition(relatedTarget as Node);
Expand Down