mirror of https://github.com/buster-so/buster.git
has suggestions through hook
This commit is contained in:
parent
8864d97d5f
commit
dfaa3d8c19
|
@ -132,7 +132,7 @@ const useUniqueSuggestions = (
|
||||||
|
|
||||||
const fourUniqueSuggestions = sampleSize(allSuggestions, 4);
|
const fourUniqueSuggestions = sampleSize(allSuggestions, 4);
|
||||||
|
|
||||||
const items: MentionInputSuggestionsProps['suggestionItems'] = fourUniqueSuggestions.map(
|
const items: MentionInputSuggestionsDropdownItem[] = fourUniqueSuggestions.map(
|
||||||
(suggestion) => ({
|
(suggestion) => ({
|
||||||
type: 'item',
|
type: 'item',
|
||||||
value: suggestion.type + suggestion.value,
|
value: suggestion.type + suggestion.value,
|
||||||
|
@ -148,7 +148,7 @@ const useUniqueSuggestions = (
|
||||||
addValueToInput: true,
|
addValueToInput: true,
|
||||||
closeOnSelect: true,
|
closeOnSelect: true,
|
||||||
},
|
},
|
||||||
];
|
] satisfies MentionInputSuggestionsProps['suggestionItems'];
|
||||||
}, [suggestedPrompts]);
|
}, [suggestedPrompts]);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { Command } from 'cmdk';
|
import { Command, useCommandState } from 'cmdk';
|
||||||
import { forwardRef, useCallback, useEffect, useImperativeHandle, useRef, useState } from 'react';
|
import { forwardRef, useCallback, useEffect, useImperativeHandle, useRef, useState } from 'react';
|
||||||
import { useMemoizedFn } from '@/hooks/useMemoizedFn';
|
import { useMemoizedFn } from '@/hooks/useMemoizedFn';
|
||||||
import { cn } from '@/lib/utils';
|
import { cn } from '@/lib/utils';
|
||||||
|
@ -51,7 +51,6 @@ export const MentionInputSuggestions = forwardRef<
|
||||||
) => {
|
) => {
|
||||||
const [hasClickedSelect, setHasClickedSelect] = useState(false);
|
const [hasClickedSelect, setHasClickedSelect] = useState(false);
|
||||||
const [value, setValue] = useState(valueProp ?? defaultValue);
|
const [value, setValue] = useState(valueProp ?? defaultValue);
|
||||||
const [hasResults, setHasResults] = useState(!!suggestionItems.length);
|
|
||||||
|
|
||||||
const commandListNavigatedRef = useRef(false);
|
const commandListNavigatedRef = useRef(false);
|
||||||
const commandRef = useRef<HTMLDivElement>(null);
|
const commandRef = useRef<HTMLDivElement>(null);
|
||||||
|
@ -106,7 +105,6 @@ export const MentionInputSuggestions = forwardRef<
|
||||||
onClick?.();
|
onClick?.();
|
||||||
if (closeSuggestionOnSelect) setHasClickedSelect(true);
|
if (closeSuggestionOnSelect) setHasClickedSelect(true);
|
||||||
onSuggestionItemClick?.(params);
|
onSuggestionItemClick?.(params);
|
||||||
setHasResults(false);
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -153,14 +151,6 @@ export const MentionInputSuggestions = forwardRef<
|
||||||
[value]
|
[value]
|
||||||
);
|
);
|
||||||
|
|
||||||
function customFilter(value: string, search: string, keywords?: string[]): number {
|
|
||||||
console.log(value, search, keywords);
|
|
||||||
// Example: exact matches rank higher, case insensitive includes rank lower
|
|
||||||
if (value.toLowerCase() === search.toLowerCase()) return 2;
|
|
||||||
if (value.toLowerCase().includes(search.toLowerCase())) return 1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Command
|
<Command
|
||||||
ref={commandRef}
|
ref={commandRef}
|
||||||
|
@ -186,26 +176,37 @@ export const MentionInputSuggestions = forwardRef<
|
||||||
/>
|
/>
|
||||||
{children && <div className="mt-3">{children}</div>}
|
{children && <div className="mt-3">{children}</div>}
|
||||||
</MentionInputSuggestionsContainer>
|
</MentionInputSuggestionsContainer>
|
||||||
{hasResults && <div className="border-b mb-1.5" />}
|
<SuggestionsSeperator />
|
||||||
<MentionInputSuggestionsList
|
<MentionInputSuggestionsList
|
||||||
show={showSuggestionList}
|
show={showSuggestionList}
|
||||||
className={cn(suggestionsContainerClassName, hasResults && 'pb-1.5')}
|
className={cn(suggestionsContainerClassName)}
|
||||||
>
|
>
|
||||||
<MentionInputSuggestionsItemsSelector
|
<MentionInputSuggestionsItemsSelector
|
||||||
suggestionItems={suggestionItems}
|
suggestionItems={suggestionItems}
|
||||||
onSelect={onSelectItem}
|
onSelect={onSelectItem}
|
||||||
addValueToInput={addSuggestionValueToInput}
|
addValueToInput={addSuggestionValueToInput}
|
||||||
closeOnSelect={closeSuggestionOnSelect}
|
closeOnSelect={closeSuggestionOnSelect}
|
||||||
hasResults={hasResults}
|
|
||||||
setHasResults={setHasResults}
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<MentionInputSuggestionsEmpty
|
<MentionInputSuggestionsEmpty emptyComponent={emptyComponent} />
|
||||||
setHasResults={setHasResults}
|
|
||||||
emptyComponent={emptyComponent}
|
|
||||||
/>
|
|
||||||
</MentionInputSuggestionsList>
|
</MentionInputSuggestionsList>
|
||||||
</Command>
|
</Command>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const SuggestionsSeperator = () => {
|
||||||
|
const hasResults = useCommandState((x) => x.filtered.count) > 0;
|
||||||
|
if (!hasResults) return null;
|
||||||
|
return <div className="border-b mb-1.5" />;
|
||||||
|
};
|
||||||
|
|
||||||
|
const customFilter = (value: string, search: string, keywords?: string[]): number => {
|
||||||
|
if (keywords?.length) {
|
||||||
|
return keywords.includes(value) ? 2 : 0;
|
||||||
|
}
|
||||||
|
// Example: exact matches rank higher, case insensitive includes rank lower
|
||||||
|
if (value.toLowerCase() === search.toLowerCase()) return 2;
|
||||||
|
if (value.toLowerCase().includes(search.toLowerCase())) return 1;
|
||||||
|
return 0;
|
||||||
|
};
|
||||||
|
|
|
@ -5,10 +5,8 @@ import { cn } from '@/lib/utils';
|
||||||
|
|
||||||
export const MentionInputSuggestionsEmpty = ({
|
export const MentionInputSuggestionsEmpty = ({
|
||||||
emptyComponent,
|
emptyComponent,
|
||||||
setHasResults,
|
|
||||||
className,
|
className,
|
||||||
}: {
|
}: {
|
||||||
setHasResults: (hasResults: boolean) => void;
|
|
||||||
className?: string;
|
className?: string;
|
||||||
emptyComponent: React.ReactNode;
|
emptyComponent: React.ReactNode;
|
||||||
}) => {
|
}) => {
|
||||||
|
@ -21,15 +19,6 @@ export const MentionInputSuggestionsEmpty = ({
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{emptyComponent}
|
{emptyComponent}
|
||||||
<SetHasResults setHasResults={setHasResults} />
|
|
||||||
</Command.Empty>
|
</Command.Empty>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const SetHasResults = ({ setHasResults }: { setHasResults: (hasResults: boolean) => void }) => {
|
|
||||||
useMount(() => {
|
|
||||||
setHasResults(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
return null;
|
|
||||||
};
|
|
||||||
|
|
|
@ -12,8 +12,6 @@ export type MentionInputSuggestionsGroupProps = MentionInputSuggestionsDropdownG
|
||||||
} & {
|
} & {
|
||||||
className?: string;
|
className?: string;
|
||||||
style?: React.CSSProperties;
|
style?: React.CSSProperties;
|
||||||
hasResults: boolean;
|
|
||||||
setHasResults: (hasResults: boolean) => void;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const MentionInputSuggestionsGroup = ({
|
export const MentionInputSuggestionsGroup = ({
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { Command } from 'cmdk';
|
import { Command, useCommandState } from 'cmdk';
|
||||||
import type React from 'react';
|
import type React from 'react';
|
||||||
import { useMount } from '@/hooks/useMount';
|
import { useMount } from '@/hooks/useMount';
|
||||||
import { cn } from '@/lib/utils';
|
import { cn } from '@/lib/utils';
|
||||||
|
@ -12,8 +12,6 @@ export type MentionInputSuggestionsItemProps = {
|
||||||
} & MentionInputSuggestionsDropdownItem & {
|
} & MentionInputSuggestionsDropdownItem & {
|
||||||
className?: string;
|
className?: string;
|
||||||
style?: React.CSSProperties;
|
style?: React.CSSProperties;
|
||||||
hasResults: boolean;
|
|
||||||
setHasResults: (hasResults: boolean) => void;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const MentionInputSuggestionsItem = ({
|
export const MentionInputSuggestionsItem = ({
|
||||||
|
@ -28,8 +26,6 @@ export const MentionInputSuggestionsItem = ({
|
||||||
type,
|
type,
|
||||||
addValueToInput,
|
addValueToInput,
|
||||||
onSelect,
|
onSelect,
|
||||||
hasResults,
|
|
||||||
setHasResults,
|
|
||||||
className,
|
className,
|
||||||
style,
|
style,
|
||||||
}: MentionInputSuggestionsItemProps) => {
|
}: MentionInputSuggestionsItemProps) => {
|
||||||
|
@ -42,6 +38,7 @@ export const MentionInputSuggestionsItem = ({
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
value={value}
|
value={value}
|
||||||
|
data-testid={`type-${type}-value-${value}`}
|
||||||
style={style}
|
style={style}
|
||||||
onSelect={() => {
|
onSelect={() => {
|
||||||
onSelect({
|
onSelect({
|
||||||
|
@ -62,21 +59,6 @@ export const MentionInputSuggestionsItem = ({
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
{label}
|
{label}
|
||||||
{!hasResults && <SetHasResults hasResults={hasResults} setHasResults={setHasResults} />}
|
|
||||||
</Command.Item>
|
</Command.Item>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const SetHasResults = ({
|
|
||||||
hasResults,
|
|
||||||
setHasResults,
|
|
||||||
}: {
|
|
||||||
hasResults: boolean;
|
|
||||||
setHasResults: (hasResults: boolean) => void;
|
|
||||||
}) => {
|
|
||||||
useMount(() => {
|
|
||||||
if (!hasResults) setHasResults(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
return null;
|
|
||||||
};
|
|
||||||
|
|
|
@ -16,8 +16,6 @@ export const MentionInputSuggestionsItemSelector = ({
|
||||||
}: {
|
}: {
|
||||||
item: MentionInputSuggestionsProps['suggestionItems'][number];
|
item: MentionInputSuggestionsProps['suggestionItems'][number];
|
||||||
onSelect: (params: MentionInputSuggestionsOnSelectParams) => void;
|
onSelect: (params: MentionInputSuggestionsOnSelectParams) => void;
|
||||||
hasResults: boolean;
|
|
||||||
setHasResults: (hasResults: boolean) => void;
|
|
||||||
} & GroupOverrideProps) => {
|
} & GroupOverrideProps) => {
|
||||||
if (item.type === 'separator') {
|
if (item.type === 'separator') {
|
||||||
return <MentionInputSuggestionsSeparator />;
|
return <MentionInputSuggestionsSeparator />;
|
||||||
|
@ -44,8 +42,6 @@ export const MentionInputSuggestionsItemsSelector = ({
|
||||||
}: {
|
}: {
|
||||||
suggestionItems: MentionInputSuggestionsProps['suggestionItems'];
|
suggestionItems: MentionInputSuggestionsProps['suggestionItems'];
|
||||||
onSelect: (params: MentionInputSuggestionsOnSelectParams) => void;
|
onSelect: (params: MentionInputSuggestionsOnSelectParams) => void;
|
||||||
hasResults: boolean;
|
|
||||||
setHasResults: (hasResults: boolean) => void;
|
|
||||||
} & GroupOverrideProps) => {
|
} & GroupOverrideProps) => {
|
||||||
if (!suggestionItems) return null;
|
if (!suggestionItems) return null;
|
||||||
return suggestionItems.map((item, index) => (
|
return suggestionItems.map((item, index) => (
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { Command } from 'cmdk';
|
import { Command, useCommandState } from 'cmdk';
|
||||||
import type React from 'react';
|
import type React from 'react';
|
||||||
import { cn } from '@/lib/utils';
|
import { cn } from '@/lib/utils';
|
||||||
|
|
||||||
|
@ -15,10 +15,12 @@ export const MentionInputSuggestionsList = ({
|
||||||
children,
|
children,
|
||||||
show = true,
|
show = true,
|
||||||
}: MentionInputSuggestionsListProps) => {
|
}: MentionInputSuggestionsListProps) => {
|
||||||
|
const hasResults = useCommandState((x) => x.filtered.count) > 0;
|
||||||
|
|
||||||
if (!show) return null;
|
if (!show) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Command.List className={cn('px-3', className)} style={style}>
|
<Command.List className={cn('px-3', hasResults && 'pb-1.5', className)} style={style}>
|
||||||
{children}
|
{children}
|
||||||
</Command.List>
|
</Command.List>
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { Command } from 'cmdk';
|
import { Command, useCommandState } from 'cmdk';
|
||||||
import type React from 'react';
|
import type React from 'react';
|
||||||
import { cn } from '@/lib/utils';
|
import { cn } from '@/lib/utils';
|
||||||
|
|
||||||
|
@ -6,6 +6,8 @@ export const MentionInputSuggestionsSeparator = ({
|
||||||
children,
|
children,
|
||||||
...props
|
...props
|
||||||
}: React.ComponentPropsWithoutRef<typeof Command.Separator>) => {
|
}: React.ComponentPropsWithoutRef<typeof Command.Separator>) => {
|
||||||
|
const hasResults = useCommandState((x) => x);
|
||||||
|
console.log(hasResults);
|
||||||
return (
|
return (
|
||||||
<Command.Separator className={cn('bg-border -mx-1 h-px my-1.5', props.className)} {...props}>
|
<Command.Separator className={cn('bg-border -mx-1 h-px my-1.5', props.className)} {...props}>
|
||||||
{children}
|
{children}
|
||||||
|
|
Loading…
Reference in New Issue