snapshot of https://github.com/makeplane/plane.git @ d868349a55de79979eb8b98701bf1702c67ad634 (2026-09-15)
Some checks failed
CodeQL / Analyze (javascript) (push) Failing after 16s
CodeQL / Analyze (python) (push) Failing after 3s
i18n sync check / check:sync (push) Failing after 3s
React Doctor / react-doctor (push) Failing after 16s
Branch Build CE / Build-Push Admin Docker Image (${{ matrix.arch }}) (push) Has been cancelled
Branch Build CE / Merge Admin Manifest (push) Has been cancelled
Branch Build CE / Build-Push Web Docker Image (${{ matrix.arch }}) (push) Has been cancelled
Branch Build CE / Merge Web Manifest (push) Has been cancelled
Branch Build CE / Build-Push Space Docker Image (${{ matrix.arch }}) (push) Has been cancelled
Branch Build CE / Merge Proxy Manifest (push) Has been cancelled
Branch Build CE / Merge Space Manifest (push) Has been cancelled
Branch Build CE / Prepare AIO Assets (push) Has been cancelled
Branch Build CE / Build Setup (push) Has been cancelled
Branch Build CE / Build-Push Live Collaboration Docker Image (${{ matrix.arch }}) (push) Has been cancelled
Branch Build CE / Merge Live Collaboration Manifest (push) Has been cancelled
Branch Build CE / Build-Push API Server Docker Image (${{ matrix.arch }}) (push) Has been cancelled
Branch Build CE / Merge API Server Manifest (push) Has been cancelled
Branch Build CE / Build-Push Proxy Docker Image (${{ matrix.arch }}) (push) Has been cancelled
Branch Build CE / Build-Push AIO Docker Image (${{ matrix.arch }}) (push) Has been cancelled
Branch Build CE / Merge AIO Manifest (push) Has been cancelled
Branch Build CE / Upload Build Assets (push) Has been cancelled
Branch Build CE / Build Release (push) Has been cancelled
Some checks failed
CodeQL / Analyze (javascript) (push) Failing after 16s
CodeQL / Analyze (python) (push) Failing after 3s
i18n sync check / check:sync (push) Failing after 3s
React Doctor / react-doctor (push) Failing after 16s
Branch Build CE / Build-Push Admin Docker Image (${{ matrix.arch }}) (push) Has been cancelled
Branch Build CE / Merge Admin Manifest (push) Has been cancelled
Branch Build CE / Build-Push Web Docker Image (${{ matrix.arch }}) (push) Has been cancelled
Branch Build CE / Merge Web Manifest (push) Has been cancelled
Branch Build CE / Build-Push Space Docker Image (${{ matrix.arch }}) (push) Has been cancelled
Branch Build CE / Merge Proxy Manifest (push) Has been cancelled
Branch Build CE / Merge Space Manifest (push) Has been cancelled
Branch Build CE / Prepare AIO Assets (push) Has been cancelled
Branch Build CE / Build Setup (push) Has been cancelled
Branch Build CE / Build-Push Live Collaboration Docker Image (${{ matrix.arch }}) (push) Has been cancelled
Branch Build CE / Merge Live Collaboration Manifest (push) Has been cancelled
Branch Build CE / Build-Push API Server Docker Image (${{ matrix.arch }}) (push) Has been cancelled
Branch Build CE / Merge API Server Manifest (push) Has been cancelled
Branch Build CE / Build-Push Proxy Docker Image (${{ matrix.arch }}) (push) Has been cancelled
Branch Build CE / Build-Push AIO Docker Image (${{ matrix.arch }}) (push) Has been cancelled
Branch Build CE / Merge AIO Manifest (push) Has been cancelled
Branch Build CE / Upload Build Assets (push) Has been cancelled
Branch Build CE / Build Release (push) Has been cancelled
This commit is contained in:
99
apps/web/core/hooks/use-expandable-search.ts
Normal file
99
apps/web/core/hooks/use-expandable-search.ts
Normal file
@@ -0,0 +1,99 @@
|
||||
/**
|
||||
* Copyright (c) 2023-present Plane Software, Inc. and contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
import { useCallback, useEffect, 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
|
||||
* Opens on click, typing, or keyboard shortcut (via PowerK Cmd+F)
|
||||
*/
|
||||
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);
|
||||
const wasKeyboardTriggeredRef = 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 keyboard shortcuts that trigger focus (Cmd+F / Ctrl+F)
|
||||
useEffect(() => {
|
||||
const handleKeyDown = (e: KeyboardEvent) => {
|
||||
if ((e.metaKey || e.ctrlKey) && e.key === "f") {
|
||||
// Mark as keyboard triggered so handleFocus knows to open
|
||||
wasKeyboardTriggeredRef.current = true;
|
||||
}
|
||||
};
|
||||
|
||||
document.addEventListener("keydown", handleKeyDown);
|
||||
return () => {
|
||||
document.removeEventListener("keydown", handleKeyDown);
|
||||
};
|
||||
}, []);
|
||||
|
||||
// Track explicit clicks
|
||||
const handleMouseDown = useCallback(() => {
|
||||
wasClickedRef.current = true;
|
||||
}, []);
|
||||
|
||||
// Open on explicit clicks or keyboard shortcut, not programmatic focus restoration
|
||||
const handleFocus = useCallback(() => {
|
||||
if (wasClickedRef.current || wasKeyboardTriggeredRef.current) {
|
||||
setIsOpen(true);
|
||||
wasClickedRef.current = false;
|
||||
wasKeyboardTriggeredRef.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,
|
||||
};
|
||||
};
|
||||
Reference in New Issue
Block a user