refactor: improve InlineCombobox context handling and optimize search functionality

This commit is contained in:
Anish Sarkar 2026-02-17 00:05:38 +05:30
parent 648b00da64
commit 0edfd116af
2 changed files with 24 additions and 11 deletions

View file

@ -28,6 +28,18 @@ import { useComposedRef, useEditorRef } from 'platejs/react';
import { cn } from '@/lib/utils';
function useRequiredComboboxContext() {
const context = useComboboxContext();
if (!context) {
throw new Error(
'InlineCombobox compound components must be rendered within InlineCombobox'
);
}
return context;
}
type FilterFn = (
item: { value: string; group?: string; keywords?: string[]; label?: string },
search: string
@ -56,7 +68,7 @@ const defaultFilter: FilterFn = (
);
return Array.from(uniqueTerms).some((keyword) =>
filterWords(keyword!, search)
filterWords(keyword as string, search)
);
};
@ -91,7 +103,7 @@ const InlineCombobox = ({
// Check if current user is the creator of this element (for Yjs collaboration)
const isCreator = React.useMemo(() => {
const elementUserId = (element as any).userId;
const elementUserId = (element as Record<string, unknown>).userId;
const currentUserId = editor.meta.userId;
// If no userId (backwards compatibility or non-Yjs), allow
@ -170,10 +182,8 @@ const InlineCombobox = ({
trigger,
showTrigger,
filter,
inputRef,
inputProps,
removeInput,
setHasEmpty,
]
);
@ -189,6 +199,8 @@ const InlineCombobox = ({
* item.
*/
React.useEffect(() => {
if (items.length === 0) return;
if (!store.getState().activeId) {
store.setActiveId(store.first());
}
@ -225,7 +237,7 @@ const InlineComboboxInput = ({
trigger,
} = React.useContext(InlineComboboxContext);
const store = useComboboxContext()!;
const store = useRequiredComboboxContext();
const value = store.useState('value');
const ref = useComposedRef(propRef, contextRef);
@ -341,14 +353,15 @@ const InlineComboboxItem = ({
const { filter, removeInput } = React.useContext(InlineComboboxContext);
const store = useComboboxContext()!;
const store = useRequiredComboboxContext();
// Optimization: Do not subscribe to value if filter is false
const search = filter && store.useState('value');
// Always call hook unconditionally; only use value if filter is active
const storeValue = store.useState('value');
const search = filter ? storeValue : '';
const visible = React.useMemo(
() =>
!filter || filter({ group, keywords, label, value }, search as string),
!filter || filter({ group, keywords, label, value }, search),
[filter, group, keywords, label, value, search]
);
@ -371,7 +384,7 @@ const InlineComboboxEmpty = ({
className,
}: React.HTMLAttributes<HTMLDivElement>) => {
const { setHasEmpty } = React.useContext(InlineComboboxContext);
const store = useComboboxContext()!;
const store = useRequiredComboboxContext();
const items = store.useState('items');
React.useEffect(() => {

View file

@ -186,7 +186,7 @@ export function SlashInputElement({
>
<InlineComboboxInput />
<InlineComboboxContent>
<InlineComboboxContent className="dark:bg-neutral-800 dark:border dark:border-neutral-700">
<InlineComboboxEmpty>No results found.</InlineComboboxEmpty>
{slashCommandGroups.map(({ heading, items }) => (