chore: remove unused ref (#203)
This commit is contained in:
parent
c1af8df24c
commit
a4542d7442
|
|
@ -156,141 +156,136 @@ export type ComboboxProps = {
|
||||||
error?: boolean;
|
error?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const Combobox = forwardRef<HTMLInputElement, ComboboxProps>(
|
export const Combobox: React.FC<ComboboxProps> = ({
|
||||||
({
|
items,
|
||||||
items,
|
selectedValue = { value: '', label: '' },
|
||||||
selectedValue = { value: '', label: '' },
|
withAutocomplete = false,
|
||||||
withAutocomplete = false,
|
leftIcon = 'search',
|
||||||
leftIcon = 'search',
|
onChange,
|
||||||
onChange,
|
onBlur,
|
||||||
onBlur,
|
error = false,
|
||||||
error = false,
|
}) => {
|
||||||
}) => {
|
const [filteredItems, setFilteredItems] = useState<ComboboxItem[]>([]);
|
||||||
const [filteredItems, setFilteredItems] = useState<ComboboxItem[]>([]);
|
const [autocompleteItems, setAutocompleteItems] = useState<ComboboxItem[]>(
|
||||||
const [autocompleteItems, setAutocompleteItems] = useState<ComboboxItem[]>(
|
[]
|
||||||
[]
|
);
|
||||||
);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// If the selected value doesn't exist in the list of items, we add it
|
// If the selected value doesn't exist in the list of items, we add it
|
||||||
if (
|
if (
|
||||||
items.filter((item) => item === selectedValue).length === 0 &&
|
items.filter((item) => item === selectedValue).length === 0 &&
|
||||||
selectedValue.value !== undefined &&
|
selectedValue.value !== undefined &&
|
||||||
autocompleteItems.length === 0 &&
|
autocompleteItems.length === 0 &&
|
||||||
withAutocomplete
|
withAutocomplete
|
||||||
) {
|
) {
|
||||||
setAutocompleteItems([selectedValue]);
|
setAutocompleteItems([selectedValue]);
|
||||||
}
|
}
|
||||||
}, [autocompleteItems.length, items, selectedValue, withAutocomplete]);
|
}, [autocompleteItems.length, items, selectedValue, withAutocomplete]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
setFilteredItems(items);
|
||||||
|
}, [items]);
|
||||||
|
|
||||||
|
const buttonRef = useRef<HTMLButtonElement>(null);
|
||||||
|
|
||||||
|
const handleSearch = useDebounce((searchValue: string) => {
|
||||||
|
if (searchValue === '') {
|
||||||
setFilteredItems(items);
|
setFilteredItems(items);
|
||||||
}, [items]);
|
|
||||||
|
|
||||||
const buttonRef = useRef<HTMLButtonElement>(null);
|
if (withAutocomplete) {
|
||||||
|
|
||||||
const handleSearch = useDebounce((searchValue: string) => {
|
|
||||||
if (searchValue === '') {
|
|
||||||
setFilteredItems(items);
|
|
||||||
|
|
||||||
if (withAutocomplete) {
|
|
||||||
setAutocompleteItems([]);
|
|
||||||
handleComboboxChange({} as ComboboxItem);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
const filteredValues = items.filter((item) =>
|
|
||||||
cleanString(item.label).startsWith(cleanString(searchValue))
|
|
||||||
);
|
|
||||||
|
|
||||||
if (withAutocomplete && filteredValues.length === 0) {
|
|
||||||
// If the search value doesn't exist in the list of items, we add it
|
|
||||||
setAutocompleteItems([{ value: searchValue, label: searchValue }]);
|
|
||||||
}
|
|
||||||
setFilteredItems(filteredValues);
|
|
||||||
}
|
|
||||||
}, 200);
|
|
||||||
|
|
||||||
const handleInputChange = (
|
|
||||||
event: React.ChangeEvent<HTMLInputElement>
|
|
||||||
): void => {
|
|
||||||
event.stopPropagation();
|
|
||||||
handleSearch(event.target.value);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleInputClick = (): void => {
|
|
||||||
buttonRef.current?.click();
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleComboboxChange = (optionSelected: ComboboxItem): void => {
|
|
||||||
onChange(optionSelected);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleLeaveTransition = (): void => {
|
|
||||||
setFilteredItems(items);
|
|
||||||
if (selectedValue.value === undefined && withAutocomplete) {
|
|
||||||
setAutocompleteItems([]);
|
setAutocompleteItems([]);
|
||||||
handleComboboxChange({} as ComboboxItem);
|
handleComboboxChange({} as ComboboxItem);
|
||||||
}
|
}
|
||||||
};
|
} else {
|
||||||
|
const filteredValues = items.filter((item) =>
|
||||||
|
cleanString(item.label).startsWith(cleanString(searchValue))
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
if (withAutocomplete && filteredValues.length === 0) {
|
||||||
<ComboboxLib
|
// If the search value doesn't exist in the list of items, we add it
|
||||||
value={selectedValue}
|
setAutocompleteItems([{ value: searchValue, label: searchValue }]);
|
||||||
by="value"
|
}
|
||||||
onChange={handleComboboxChange}
|
setFilteredItems(filteredValues);
|
||||||
>
|
}
|
||||||
{({ open }) => (
|
}, 200);
|
||||||
<div className="relative">
|
|
||||||
<ComboboxInput
|
|
||||||
onChange={handleInputChange}
|
|
||||||
onClick={handleInputClick}
|
|
||||||
open={open}
|
|
||||||
leftIcon={leftIcon}
|
|
||||||
onBlur={onBlur}
|
|
||||||
error={error}
|
|
||||||
/>
|
|
||||||
<ComboboxLib.Button ref={buttonRef} className="hidden" />
|
|
||||||
|
|
||||||
<Transition
|
const handleInputChange = (
|
||||||
show={open}
|
event: React.ChangeEvent<HTMLInputElement>
|
||||||
as={Fragment}
|
): void => {
|
||||||
enter="transition duration-400 ease-out"
|
event.stopPropagation();
|
||||||
leave="transition ease-out duration-100"
|
handleSearch(event.target.value);
|
||||||
leaveFrom="opacity-100"
|
};
|
||||||
leaveTo="opacity-0"
|
|
||||||
afterLeave={handleLeaveTransition}
|
const handleInputClick = (): void => {
|
||||||
>
|
buttonRef.current?.click();
|
||||||
<ComboboxLib.Options className="absolute max-h-60 w-full z-10 overflow-auto rounded-b-xl border-solid border-slate6 border bg-black pt-2 px-3 text-base focus:outline-none sm:text-sm">
|
};
|
||||||
{[...autocompleteItems, ...filteredItems].length === 0 ||
|
|
||||||
filteredItems === undefined ? (
|
const handleComboboxChange = (optionSelected: ComboboxItem): void => {
|
||||||
<NoResults />
|
onChange(optionSelected);
|
||||||
) : (
|
};
|
||||||
<>
|
|
||||||
{autocompleteItems.length > 0 && <span>Create new</span>}
|
const handleLeaveTransition = (): void => {
|
||||||
{autocompleteItems.map(
|
setFilteredItems(items);
|
||||||
(autocompleteOption: ComboboxItem) => (
|
if (selectedValue.value === undefined && withAutocomplete) {
|
||||||
<ComboboxOption
|
setAutocompleteItems([]);
|
||||||
key={autocompleteOption.value}
|
handleComboboxChange({} as ComboboxItem);
|
||||||
option={autocompleteOption}
|
}
|
||||||
/>
|
};
|
||||||
)
|
|
||||||
)}
|
return (
|
||||||
{autocompleteItems.length > 0 &&
|
<ComboboxLib
|
||||||
filteredItems.length > 0 && (
|
value={selectedValue}
|
||||||
<Separator css={{ mb: '$2' }} />
|
by="value"
|
||||||
)}
|
onChange={handleComboboxChange}
|
||||||
{filteredItems.map((option: ComboboxItem) => (
|
>
|
||||||
<ComboboxOption key={option.value} option={option} />
|
{({ open }) => (
|
||||||
))}
|
<div className="relative">
|
||||||
</>
|
<ComboboxInput
|
||||||
)}
|
onChange={handleInputChange}
|
||||||
</ComboboxLib.Options>
|
onClick={handleInputClick}
|
||||||
</Transition>
|
open={open}
|
||||||
</div>
|
leftIcon={leftIcon}
|
||||||
)}
|
onBlur={onBlur}
|
||||||
</ComboboxLib>
|
error={error}
|
||||||
);
|
/>
|
||||||
}
|
<ComboboxLib.Button ref={buttonRef} className="hidden" />
|
||||||
);
|
|
||||||
|
<Transition
|
||||||
|
show={open}
|
||||||
|
as={Fragment}
|
||||||
|
enter="transition duration-400 ease-out"
|
||||||
|
leave="transition ease-out duration-100"
|
||||||
|
leaveFrom="opacity-100"
|
||||||
|
leaveTo="opacity-0"
|
||||||
|
afterLeave={handleLeaveTransition}
|
||||||
|
>
|
||||||
|
<ComboboxLib.Options className="absolute max-h-60 w-full z-10 overflow-auto rounded-b-xl border-solid border-slate6 border bg-black pt-2 px-3 text-base focus:outline-none sm:text-sm">
|
||||||
|
{[...autocompleteItems, ...filteredItems].length === 0 ||
|
||||||
|
filteredItems === undefined ? (
|
||||||
|
<NoResults />
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
{autocompleteItems.length > 0 && <span>Create new</span>}
|
||||||
|
{autocompleteItems.map((autocompleteOption: ComboboxItem) => (
|
||||||
|
<ComboboxOption
|
||||||
|
key={autocompleteOption.value}
|
||||||
|
option={autocompleteOption}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
{autocompleteItems.length > 0 && filteredItems.length > 0 && (
|
||||||
|
<Separator css={{ mb: '$2' }} />
|
||||||
|
)}
|
||||||
|
{filteredItems.map((option: ComboboxItem) => (
|
||||||
|
<ComboboxOption key={option.value} option={option} />
|
||||||
|
))}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</ComboboxLib.Options>
|
||||||
|
</Transition>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</ComboboxLib>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
Combobox.displayName = 'Combobox';
|
Combobox.displayName = 'Combobox';
|
||||||
|
|
|
||||||
|
|
@ -134,48 +134,45 @@ export abstract class Form {
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
static readonly Combobox = forwardRef<HTMLInputElement, Form.ComboboxProps>(
|
static readonly Combobox: React.FC<Form.ComboboxProps> = (props) => {
|
||||||
(props, ref) => {
|
const {
|
||||||
const {
|
id,
|
||||||
id,
|
validators,
|
||||||
validators,
|
value: [value, setValue],
|
||||||
value: [value, setValue],
|
validationEnabled: [validationEnabled, setValidationEnabled],
|
||||||
validationEnabled: [validationEnabled, setValidationEnabled],
|
} = useFormFieldContext();
|
||||||
} = useFormFieldContext();
|
|
||||||
|
|
||||||
const comboboxValue = useMemo(() => {
|
const comboboxValue = useMemo(() => {
|
||||||
// if it's with autocomplete maybe won't be on the items list
|
// if it's with autocomplete maybe won't be on the items list
|
||||||
const item = props.items.find((item) => item.label === value);
|
const item = props.items.find((item) => item.label === value);
|
||||||
if (props.withAutocomplete && !item && value !== '') {
|
if (props.withAutocomplete && !item && value !== '') {
|
||||||
//return the selected value if the item doesn't exist
|
//return the selected value if the item doesn't exist
|
||||||
return { label: value, value: value };
|
return { label: value, value: value };
|
||||||
}
|
}
|
||||||
return item;
|
return item;
|
||||||
}, [props.items, props.withAutocomplete, value]);
|
}, [props.items, props.withAutocomplete, value]);
|
||||||
|
|
||||||
const isValid = useFormFieldValidatorValue(id, validators, value);
|
const isValid = useFormFieldValidatorValue(id, validators, value);
|
||||||
|
|
||||||
const handleComboboxChange = (option: ComboboxItem): void => {
|
const handleComboboxChange = (option: ComboboxItem): void => {
|
||||||
if (props.onChange) props.onChange(option);
|
if (props.onChange) props.onChange(option);
|
||||||
setValue(option.label);
|
setValue(option.label);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleComboboxBlur = (): void => {
|
const handleComboboxBlur = (): void => {
|
||||||
setValidationEnabled(true);
|
setValidationEnabled(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Combobox
|
<Combobox
|
||||||
ref={ref}
|
{...props}
|
||||||
{...props}
|
onChange={handleComboboxChange}
|
||||||
onChange={handleComboboxChange}
|
selectedValue={comboboxValue || ({} as ComboboxItem)}
|
||||||
selectedValue={comboboxValue || ({} as ComboboxItem)}
|
onBlur={handleComboboxBlur}
|
||||||
onBlur={handleComboboxBlur}
|
error={validationEnabled && !isValid}
|
||||||
error={validationEnabled && !isValid}
|
/>
|
||||||
/>
|
);
|
||||||
);
|
};
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
static readonly ColorPicker: React.FC<Form.ColorPickerProps> = ({
|
static readonly ColorPicker: React.FC<Form.ColorPickerProps> = ({
|
||||||
logo,
|
logo,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue