[WEB-5536] feat: prevent search panels from reopening on programmatic focus restoration (#8207)
This commit is contained in:
parent
f428c3bdaf
commit
980428b204
6 changed files with 125 additions and 47 deletions
75
apps/web/core/hooks/use-expandable-search.ts
Normal file
75
apps/web/core/hooks/use-expandable-search.ts
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
import { useCallback, useRef, useState } from "react";
|
||||
import { useOutsideClickDetector } from "@plane/hooks";
|
||||
|
||||
type UseExpandableSearchOptions = {
|
||||
onClose?: () => void;
|
||||
};
|
||||
|
||||
/**
|
||||
* Custom hook for expandable search input behavior
|
||||
* Handles focus management to prevent unwanted opening on programmatic focus restoration
|
||||
*/
|
||||
export const useExpandableSearch = (options?: UseExpandableSearchOptions) => {
|
||||
const { onClose } = options || {};
|
||||
|
||||
// states
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
|
||||
// refs
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
const inputRef = useRef<HTMLInputElement>(null);
|
||||
const wasClickedRef = useRef<boolean>(false);
|
||||
|
||||
// Handle close
|
||||
const handleClose = useCallback(() => {
|
||||
setIsOpen(false);
|
||||
inputRef.current?.blur();
|
||||
onClose?.();
|
||||
}, [onClose]);
|
||||
|
||||
// Outside click handler - memoized to prevent unnecessary re-registrations
|
||||
const handleOutsideClick = useCallback(() => {
|
||||
if (isOpen) {
|
||||
handleClose();
|
||||
}
|
||||
}, [isOpen, handleClose]);
|
||||
|
||||
// Outside click detection
|
||||
useOutsideClickDetector(containerRef, handleOutsideClick);
|
||||
|
||||
// Track explicit clicks
|
||||
const handleMouseDown = useCallback(() => {
|
||||
wasClickedRef.current = true;
|
||||
}, []);
|
||||
|
||||
// Only open on explicit clicks, not programmatic focus
|
||||
const handleFocus = useCallback(() => {
|
||||
if (wasClickedRef.current) {
|
||||
setIsOpen(true);
|
||||
wasClickedRef.current = false;
|
||||
}
|
||||
}, []);
|
||||
|
||||
// Helper to open panel (for typing/onChange)
|
||||
const openPanel = useCallback(() => {
|
||||
if (!isOpen) {
|
||||
setIsOpen(true);
|
||||
}
|
||||
}, [isOpen]);
|
||||
|
||||
return {
|
||||
// State
|
||||
isOpen,
|
||||
setIsOpen,
|
||||
|
||||
// Refs
|
||||
containerRef,
|
||||
inputRef,
|
||||
|
||||
// Handlers
|
||||
handleClose,
|
||||
handleMouseDown,
|
||||
handleFocus,
|
||||
openPanel,
|
||||
};
|
||||
};
|
||||
Loading…
Add table
Add a link
Reference in a new issue