diff --git a/surfsense_web/components/ui/inline-combobox.tsx b/surfsense_web/components/ui/inline-combobox.tsx index cf056d3d8..bc2ce1a3d 100644 --- a/surfsense_web/components/ui/inline-combobox.tsx +++ b/surfsense_web/components/ui/inline-combobox.tsx @@ -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).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) => { const { setHasEmpty } = React.useContext(InlineComboboxContext); - const store = useComboboxContext()!; + const store = useRequiredComboboxContext(); const items = store.useState('items'); React.useEffect(() => { diff --git a/surfsense_web/components/ui/slash-node.tsx b/surfsense_web/components/ui/slash-node.tsx index 7bd3c0969..09df86e86 100644 --- a/surfsense_web/components/ui/slash-node.tsx +++ b/surfsense_web/components/ui/slash-node.tsx @@ -186,7 +186,7 @@ export function SlashInputElement({ > - + No results found. {slashCommandGroups.map(({ heading, items }) => (