feat(ui): iterate on model combobox (wip)

This commit is contained in:
psychedelicious
2025-04-15 20:15:30 +10:00
parent 5aed2b315d
commit de32ed23a7
2 changed files with 39 additions and 26 deletions

View File

@@ -34,6 +34,22 @@ const DefaultGroupHeaderComponent = ({ id }: { id: string }) => {
return <Text fontWeight="bold">{id}</Text>;
};
const DefaultNoOptionsFallback = () => {
return (
<Flex w="full" h="full" alignItems="center" justifyContent="center">
<Text variant="subtext">No options available</Text>
</Flex>
);
};
const DefaultNoMatchesFallback = () => {
return (
<Flex w="full" h="full" alignItems="center" justifyContent="center">
<Text variant="subtext">No matching options</Text>
</Flex>
);
};
export type PickerProps<T extends object> = {
options: (T | Group<T>)[];
getOptionId: (option: T) => string;
@@ -49,15 +65,21 @@ export type PickerProps<T extends object> = {
GroupHeaderComponent?: React.ComponentType<{ group: Group<T> }>;
};
export const getRegex = (searchTerm: string) =>
new RegExp(
searchTerm
.trim()
.replace(/[-[\]{}()*+!<=:?./\\^$|#,]/g, '')
.split(' ')
.join('.*'),
'gi'
);
export const getRegex = (searchTerm: string) => {
const terms = searchTerm
.trim()
.replace(/[-[\]{}()*+!<=:?./\\^$|#,]/g, '')
.split(' ')
.filter((term) => term.length > 0);
if (terms.length === 0) {
return new RegExp('', 'gi');
}
// Create positive lookaheads for each term - matches in any order
const pattern = terms.map((term) => `(?=.*${term})`).join('');
return new RegExp(`${pattern}.+`, 'i');
};
const getFirstOption = <T extends object>(options: (T | Group<T>)[]): T | undefined => {
const firstOptionOrGroup = options[0];
@@ -121,8 +143,8 @@ export const Picker = typedMemo(<T extends object>(props: PickerProps<T>) => {
handleRef,
isMatch,
getIsDisabled,
noMatchesFallback,
noOptionsFallback,
noMatchesFallback = <DefaultNoMatchesFallback />,
noOptionsFallback = <DefaultNoOptionsFallback />,
onClose,
onSelect,
selectedItem,

View File

@@ -216,12 +216,10 @@ const MainModelPicker = memo(() => {
getOptionId={getOptionId}
onSelect={onSelect}
selectedItem={modelConfig}
getIsDisabled={getIsDisabled}
// getIsDisabled={getIsDisabled}
isMatch={isMatch}
OptionComponent={PickerItemComponent}
GroupHeaderComponent={PickerGroupHeaderComponent}
noOptionsFallback={<Text>{t('common.noOptions')}</Text>}
noMatchesFallback={<Text>{t('common.noMatches')}</Text>}
/>
</PopoverBody>
</PopoverContent>
@@ -233,7 +231,7 @@ MainModelPicker.displayName = 'MainModelPicker';
const PickerGroupHeaderComponent = memo(
({ group }: { group: Group<AnyModelConfig, { name: string; description: string }> }) => {
return (
<Flex flexDir="column">
<Flex flexDir="column" ps={8}>
<Text fontSize="sm" fontWeight="semibold">
{group.data.name}
</Text>
@@ -276,18 +274,11 @@ const BASE_KEYWORDS: { [key in BaseModelType]?: string[] } = {
const isMatch = (model: AnyModelConfig, searchTerm: string) => {
const regex = getRegex(searchTerm);
const bases = BASE_KEYWORDS[model.base] ?? [model.base];
const testString =
`${model.name} ${bases.join(' ')} ${model.type} ${model.description ?? ''} ${model.format}`.toLowerCase();
if (
model.name.toLowerCase().includes(searchTerm) ||
regex.test(model.name) ||
(BASE_KEYWORDS[model.base] ?? [model.base]).some((kw) => kw.toLowerCase().includes(searchTerm) || regex.test(kw)) ||
model.type.toLowerCase().includes(searchTerm) ||
regex.test(model.type) ||
(model.description ?? '').toLowerCase().includes(searchTerm) ||
regex.test(model.description ?? '') ||
model.format.toLowerCase().includes(searchTerm) ||
regex.test(model.format)
) {
if (testString.includes(searchTerm) || regex.test(testString)) {
return true;
}