Files
cinny/src/app/components/editor/autocomplete/AutocompleteMenu.tsx
T
jared 0d303169f2 fix: prevent editor blur on any click inside autocomplete menu
FocusTrap monitors focusin events and can redirect focus into the menu
container (blurring the editor) before individual MenuItem onMouseDown
handlers fire. Adding preventDefault at the container level ensures no
click anywhere inside the menu can steal focus from the editor.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 21:35:38 -04:00

53 lines
1.8 KiB
TypeScript

import React, { ReactNode } from 'react';
import FocusTrap from 'focus-trap-react';
import { isKeyHotkey } from 'is-hotkey';
import { Header, Menu, Scroll, config } from 'folds';
import * as css from './AutocompleteMenu.css';
import { preventScrollWithArrowKey, stopPropagation } from '../../../utils/keyboard';
import { useAlive } from '../../../hooks/useAlive';
type AutocompleteMenuProps = {
requestClose: () => void;
headerContent: ReactNode;
children: ReactNode;
};
export function AutocompleteMenu({ headerContent, requestClose, children }: AutocompleteMenuProps) {
const alive = useAlive();
const handleDeactivate = () => {
if (alive()) {
// The component is unmounted so we will not call for `requestClose`
requestClose();
}
};
return (
<div className={css.AutocompleteMenuBase} onMouseDown={(e) => e.preventDefault()}>
<div className={css.AutocompleteMenuContainer}>
<FocusTrap
focusTrapOptions={{
initialFocus: false,
onPostDeactivate: handleDeactivate,
returnFocusOnDeactivate: false,
clickOutsideDeactivates: true,
allowOutsideClick: true,
isKeyForward: (evt: KeyboardEvent) => isKeyHotkey('arrowdown', evt),
isKeyBackward: (evt: KeyboardEvent) => isKeyHotkey('arrowup', evt),
escapeDeactivates: stopPropagation,
}}
>
<Menu className={css.AutocompleteMenu}>
<Header className={css.AutocompleteMenuHeader} size="400">
{headerContent}
</Header>
<Scroll style={{ flexGrow: 1 }} onKeyDown={preventScrollWithArrowKey}>
<div style={{ padding: config.space.S200 }}>{children}</div>
</Scroll>
</Menu>
</FocusTrap>
</div>
</div>
);
}