From 877d469870f2260326f96905476303cda7c348b4 Mon Sep 17 00:00:00 2001 From: Kinbaum Date: Sat, 19 Nov 2022 06:19:51 -0500 Subject: [PATCH] [@mantine/hooks] Allow use-focus-trap and use-click-outside hooks to work with shadow DOM (#2982) * fix: allow hook to work with shadow DOM * fix: allow hook to work with shadow DOM * fix: allow hook to work with shadow DOM * fix: allow hook to work with shadow DOM * fix: allow hook to work with shadow DOM * fix: ts error with `activeElement` * fix: eslint issues with line length * fix: running prettier on changed files --- src/mantine-hooks/src/use-click-outside/use-click-outside.ts | 2 +- src/mantine-hooks/src/use-focus-trap/create-aria-hider.ts | 2 +- src/mantine-hooks/src/use-focus-trap/scope-tab.ts | 4 ++-- src/mantine-hooks/src/use-focus-trap/tabbable.ts | 2 +- src/mantine-hooks/src/use-focus-trap/use-focus-trap.ts | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/mantine-hooks/src/use-click-outside/use-click-outside.ts b/src/mantine-hooks/src/use-click-outside/use-click-outside.ts index 45b0f50bba8..e12f69f326e 100644 --- a/src/mantine-hooks/src/use-click-outside/use-click-outside.ts +++ b/src/mantine-hooks/src/use-click-outside/use-click-outside.ts @@ -15,7 +15,7 @@ export function useClickOutside( if (Array.isArray(nodes)) { const shouldIgnore = target?.hasAttribute('data-ignore-outside-clicks') || !document.body.contains(target); - const shouldTrigger = nodes.every((node) => !!node && !node.contains(target)); + const shouldTrigger = nodes.every((node) => !!node && !event.composedPath().includes(node)); shouldTrigger && !shouldIgnore && handler(); } else if (ref.current && !ref.current.contains(target)) { handler(); diff --git a/src/mantine-hooks/src/use-focus-trap/create-aria-hider.ts b/src/mantine-hooks/src/use-focus-trap/create-aria-hider.ts index 05a9383000c..67e7c472564 100644 --- a/src/mantine-hooks/src/use-focus-trap/create-aria-hider.ts +++ b/src/mantine-hooks/src/use-focus-trap/create-aria-hider.ts @@ -9,7 +9,7 @@ export function createAriaHider( ) { const rootNodes: Value[] = Array.from(document.querySelectorAll(selector)).map( (node) => { - if (node.contains(containerNode)) { + if (node?.shadowRoot?.contains(containerNode) || node.contains(containerNode)) { return undefined; } diff --git a/src/mantine-hooks/src/use-focus-trap/scope-tab.ts b/src/mantine-hooks/src/use-focus-trap/scope-tab.ts index 0962d1441b0..a48fb1871ee 100644 --- a/src/mantine-hooks/src/use-focus-trap/scope-tab.ts +++ b/src/mantine-hooks/src/use-focus-trap/scope-tab.ts @@ -7,8 +7,8 @@ export function scopeTab(node: HTMLElement, event: KeyboardEvent) { return; } const finalTabbable = tabbable[event.shiftKey ? 0 : tabbable.length - 1]; - const leavingFinalTabbable = - finalTabbable === document.activeElement || node === document.activeElement; + const root = node.getRootNode() as unknown as DocumentOrShadowRoot; + const leavingFinalTabbable = finalTabbable === root.activeElement || node === root.activeElement; if (!leavingFinalTabbable) { return; diff --git a/src/mantine-hooks/src/use-focus-trap/tabbable.ts b/src/mantine-hooks/src/use-focus-trap/tabbable.ts index ba0502303e2..e97deea14f7 100644 --- a/src/mantine-hooks/src/use-focus-trap/tabbable.ts +++ b/src/mantine-hooks/src/use-focus-trap/tabbable.ts @@ -21,7 +21,7 @@ function visible(element: HTMLElement) { let parentElement: HTMLElement = element; while (parentElement) { - if (parentElement === document.body) { + if (parentElement === document.body || parentElement.nodeType === 11) { break; } diff --git a/src/mantine-hooks/src/use-focus-trap/use-focus-trap.ts b/src/mantine-hooks/src/use-focus-trap/use-focus-trap.ts index 2f69fcad60a..3e95ce130c6 100644 --- a/src/mantine-hooks/src/use-focus-trap/use-focus-trap.ts +++ b/src/mantine-hooks/src/use-focus-trap/use-focus-trap.ts @@ -45,7 +45,7 @@ export function useFocusTrap(active = true): (instance: HTMLElement | null) => v // Delay processing the HTML node by a frame. This ensures focus is assigned correctly. setTimeout(() => { - if (node.ownerDocument) { + if (node.getRootNode()) { processNode(); } else if (process.env.NODE_ENV === 'development') { // eslint-disable-next-line no-console