diff --git a/src/hooks/usePickerInput.ts b/src/hooks/usePickerInput.ts index b08ed6389e07..318dca4c1be8 100644 --- a/src/hooks/usePickerInput.ts +++ b/src/hooks/usePickerInput.ts @@ -1,7 +1,7 @@ import type * as React from 'react'; import { useState, useEffect, useRef } from 'react'; import KeyCode from 'rc-util/lib/KeyCode'; -import { addGlobalMouseDownEvent } from '../utils/uiUtil'; +import { addGlobalMouseDownEvent, getTargetFromEvent } from '../utils/uiUtil'; export default function usePickerInput({ open, @@ -21,10 +21,7 @@ export default function usePickerInput({ isClickOutside: (clickElement: EventTarget | null) => boolean; triggerOpen: (open: boolean) => void; forwardKeyDown: (e: React.KeyboardEvent) => boolean; - onKeyDown: ( - e: React.KeyboardEvent, - preventDefault: () => void, - ) => void; + onKeyDown: (e: React.KeyboardEvent, preventDefault: () => void) => void; blurToCancel?: boolean; onSubmit: () => void | boolean; onCancel: () => void; @@ -49,7 +46,7 @@ export default function usePickerInput({ setTyping(true); triggerOpen(true); }, - onKeyDown: e => { + onKeyDown: (e) => { const preventDefault = (): void => { preventDefaultRef.current = true; }; @@ -98,7 +95,7 @@ export default function usePickerInput({ } }, - onFocus: e => { + onFocus: (e) => { setTyping(true); setFocused(true); @@ -107,7 +104,7 @@ export default function usePickerInput({ } }, - onBlur: e => { + onBlur: (e) => { if (preventBlurRef.current || !isClickOutside(document.activeElement)) { preventBlurRef.current = false; return; @@ -145,16 +142,20 @@ export default function usePickerInput({ // Global click handler useEffect(() => - addGlobalMouseDownEvent(({ target }: MouseEvent) => { + addGlobalMouseDownEvent((e: MouseEvent) => { + const target = getTargetFromEvent(e); + if (open) { - if (!isClickOutside(target)) { + const clickedOutside = isClickOutside(target); + + if (!clickedOutside) { preventBlurRef.current = true; // Always set back in case `onBlur` prevented by user requestAnimationFrame(() => { preventBlurRef.current = false; }); - } else if (!focused) { + } else if (!focused || clickedOutside) { triggerOpen(false); } } diff --git a/src/utils/uiUtil.ts b/src/utils/uiUtil.ts index 1cc0e35281aa..1ac765c7c083 100644 --- a/src/utils/uiUtil.ts +++ b/src/utils/uiUtil.ts @@ -201,7 +201,7 @@ export function addGlobalMouseDownEvent(callback: ClickEventHandler) { if (!globalClickFunc && typeof window !== 'undefined' && window.addEventListener) { globalClickFunc = (e: MouseEvent) => { // Clone a new list to avoid repeat trigger events - [...clickCallbacks].forEach(queueFunc => { + [...clickCallbacks].forEach((queueFunc) => { queueFunc(e); }); }; @@ -219,6 +219,17 @@ export function addGlobalMouseDownEvent(callback: ClickEventHandler) { }; } +export function getTargetFromEvent(e: Event) { + const target = e.target as HTMLElement; + + // get target if in shadow dom + if (e.composed && target.shadowRoot) { + return (e.composedPath?.()[0] || target) as HTMLElement; + } + + return target; +} + // ====================== Mode ====================== const getYearNextMode = (next: PanelMode): PanelMode => { if (next === 'month' || next === 'date') { @@ -261,5 +272,5 @@ export function elementsContains( elements: (HTMLElement | undefined | null)[], target: HTMLElement, ) { - return elements.some(ele => ele && ele.contains(target)); + return elements.some((ele) => ele && ele.contains(target)); }