buster/apps/web/src/components/ui/inputs/BusterInput/BusterInput.tsx

122 lines
3.5 KiB
TypeScript
Raw Normal View History

2025-09-12 11:39:08 +08:00
import { Command } from 'cmdk';
2025-09-12 13:43:51 +08:00
import { useCallback, useState } from 'react';
import { useMemoizedFn } from '@/hooks/useMemoizedFn';
import type { BusterInputProps, BusterOnSelectParams } from './BusterInput.types';
2025-09-13 00:16:30 +08:00
import { BusterInputContainer } from './BusterInputContainer';
2025-09-12 11:39:08 +08:00
import { BusterInputEmpty } from './BusterInputEmpty';
2025-09-12 13:43:51 +08:00
import { BusterInputList } from './BusterInputList';
import { BusterItemsSelector } from './BusterItemSelector';
import { BusterMentionsInput } from './BusterMentionsInput';
2025-09-12 11:39:08 +08:00
2025-09-12 13:43:51 +08:00
export const BusterInput = ({
placeholder,
defaultValue,
value: valueProp,
emptyComponent,
submitting,
onSubmit,
2025-09-12 13:47:24 +08:00
disabled: disabledGlobal = false,
2025-09-12 13:43:51 +08:00
onStop,
sendIcon,
secondaryActions,
variant = 'default',
onChange,
ariaLabel = 'Buster Input',
2025-09-30 00:37:45 +08:00
readOnly,
autoFocus,
2025-09-16 13:16:31 +08:00
//suggestions
suggestionItems,
closeSuggestionOnSelect = true,
addSuggestionValueToInput = true,
onSuggestionItemClick,
2025-09-13 00:16:30 +08:00
filter,
2025-09-16 13:16:31 +08:00
shouldFilter,
//mentions
onMentionItemClick,
mentions,
2025-09-12 13:43:51 +08:00
}: BusterInputProps) => {
const [hasClickedSelect, setHasClickedSelect] = useState(false);
2025-09-12 11:39:08 +08:00
const [value, setValue] = useState(valueProp ?? defaultValue);
2025-09-16 13:16:31 +08:00
const showSuggestionList = !hasClickedSelect && suggestionItems.length > 0;
2025-09-12 11:39:08 +08:00
2025-09-12 13:43:51 +08:00
const onChangeInputValue = useCallback((value: string) => {
setValue(value);
setHasClickedSelect(false);
2025-09-12 13:47:24 +08:00
onChange?.(value);
2025-09-12 13:43:51 +08:00
}, []);
2025-09-12 11:39:08 +08:00
2025-09-12 13:43:51 +08:00
const onSelectItem = useMemoizedFn(({ onClick, ...params }: BusterOnSelectParams) => {
const { addValueToInput, value, loading, inputValue, label, disabled } = params;
if (disabled) {
console.warn('Item is disabled', params);
return;
}
if (submitting) {
console.warn('Input is submitting');
return;
}
if (loading) {
console.warn('Item is loading', params);
return;
}
2025-09-30 00:37:45 +08:00
console.log('onSelectItem', addValueToInput, params);
2025-09-12 13:43:51 +08:00
if (addValueToInput) setValue(inputValue ?? String(label));
onClick?.();
2025-09-16 13:16:31 +08:00
if (closeSuggestionOnSelect) setHasClickedSelect(true);
onSuggestionItemClick?.(params);
2025-09-12 13:43:51 +08:00
});
2025-09-12 13:47:24 +08:00
const onSubmitPreflight = useMemoizedFn((value: string) => {
if (submitting) {
console.warn('Input is submitting');
return;
}
if (disabledGlobal) {
console.warn('Input is disabledGlobal');
return;
}
onSubmit(value);
});
const onStopPreflight = useMemoizedFn(() => {
onStop();
});
2025-09-12 13:43:51 +08:00
return (
2025-09-13 00:16:30 +08:00
<Command label={ariaLabel} className="relative">
<BusterInputContainer
onSubmit={onSubmitPreflight}
onStop={onStopPreflight}
submitting={submitting}
disabled={disabledGlobal}
sendIcon={sendIcon}
secondaryActions={secondaryActions}
variant={variant}
>
2025-09-12 13:43:51 +08:00
<BusterMentionsInput
defaultValue={defaultValue}
2025-09-30 00:37:45 +08:00
readOnly={readOnly}
autoFocus={autoFocus}
2025-09-12 13:43:51 +08:00
placeholder={placeholder}
mentions={mentions}
value={value}
2025-09-30 00:37:45 +08:00
onChange={onChangeInputValue}
2025-09-13 00:16:30 +08:00
shouldFilter={shouldFilter}
filter={filter}
2025-09-16 13:16:31 +08:00
onMentionItemClick={onMentionItemClick}
2025-09-12 13:43:51 +08:00
/>
2025-09-13 00:16:30 +08:00
</BusterInputContainer>
2025-09-16 13:16:31 +08:00
<BusterInputList show={showSuggestionList}>
2025-09-13 00:16:30 +08:00
<BusterItemsSelector
2025-09-16 13:16:31 +08:00
suggestionItems={suggestionItems}
2025-09-13 00:16:30 +08:00
onSelect={onSelectItem}
2025-09-16 13:16:31 +08:00
addValueToInput={addSuggestionValueToInput}
closeOnSelect={closeSuggestionOnSelect}
2025-09-13 00:16:30 +08:00
/>
{emptyComponent && <BusterInputEmpty>{emptyComponent}</BusterInputEmpty>}
</BusterInputList>
</Command>
2025-09-12 11:39:08 +08:00
);
};