@gravity-ui/uikit
Version:
Gravity UI base styling and components
54 lines (53 loc) • 2.35 kB
JavaScript
import * as React from 'react';
import { SyntheticFocusEvent } from "./SyntheticFocusEvent.js";
// React does not fire onBlur when an element is disabled https://github.com/facebook/react/issues/9142
export function useSyntheticBlurEvent(onBlur) {
const stateRef = React.useRef({
isFocused: false,
observer: null,
});
React.useEffect(() => {
const state = stateRef.current;
return () => {
if (state.observer) {
state.observer.disconnect();
state.observer = null;
}
};
}, []);
const handleFocus = React.useCallback((event) => {
const target = event.target;
if (target instanceof HTMLButtonElement ||
target instanceof HTMLInputElement ||
target instanceof HTMLTextAreaElement ||
target instanceof HTMLSelectElement) {
stateRef.current.isFocused = true;
const handleBlur = (e) => {
stateRef.current.isFocused = false;
if (target.disabled) {
onBlur?.(new SyntheticFocusEvent('blur', e));
}
if (stateRef.current.observer) {
stateRef.current.observer.disconnect();
stateRef.current.observer = null;
}
};
// TS can't resolve correct definition for addEventListener when target is union type
// @ts-expect-error
target.addEventListener('focusout', handleBlur, { once: true });
const observer = new MutationObserver(() => {
if (stateRef.current.isFocused && target.disabled) {
observer.disconnect();
stateRef.current.observer = null;
const relatedTarget = target === document.activeElement ? null : document.activeElement;
target.dispatchEvent(new FocusEvent('blur', { relatedTarget }));
target.dispatchEvent(new FocusEvent('focusout', { relatedTarget, bubbles: true }));
}
});
observer.observe(target, { attributes: true, attributeFilter: ['disabled'] });
stateRef.current.observer = observer;
}
}, [onBlur]);
return handleFocus;
}
//# sourceMappingURL=useSyntheticBlurEvent.js.map