Add InputDropdown

This commit is contained in:
David Corbitt
2023-08-14 23:02:08 -07:00
parent 9a9cbe8fd4
commit 634739c045
4 changed files with 137 additions and 32 deletions

View File

@@ -0,0 +1,89 @@
import {
Input,
InputGroup,
InputRightElement,
Icon,
Popover,
PopoverTrigger,
PopoverContent,
VStack,
HStack,
Button,
Text,
useDisclosure,
type PopoverContentProps,
type InputGroupProps,
} from "@chakra-ui/react";
import { FiChevronDown } from "react-icons/fi";
import { BiCheck } from "react-icons/bi";
type InputDropdownProps<T> = {
options: ReadonlyArray<T>;
selectedOption: T;
onSelect: (option: T) => void;
inputGroupProps?: InputGroupProps;
popoverContentProps?: PopoverContentProps;
};
const InputDropdown = <T,>({
options,
selectedOption,
onSelect,
inputGroupProps,
popoverContentProps,
}: InputDropdownProps<T>) => {
const popover = useDisclosure();
return (
<Popover placement="bottom-start" {...popover}>
<PopoverTrigger>
<InputGroup cursor="pointer" w={360} {...inputGroupProps}>
<Input
value={selectedOption as string}
cursor="pointer"
borderWidth={popover.isOpen ? 2 : undefined}
borderColor={popover.isOpen ? "blue.500" : undefined}
_hover={popover.isOpen ? { borderColor: "blue.500" } : undefined}
contentEditable={false}
// disable focus
onFocus={(e) => {
e.target.blur();
}}
/>
<InputRightElement>
<Icon as={FiChevronDown} />
</InputRightElement>
</InputGroup>
</PopoverTrigger>
<PopoverContent boxShadow="0 0 40px 4px rgba(0, 0, 0, 0.1);" w={224} {...popoverContentProps}>
<VStack spacing={0}>
{options?.map((option, index) => (
<HStack
key={index}
as={Button}
onClick={() => {
onSelect(option);
popover.onClose();
}}
w="full"
variant="ghost"
justifyContent="space-between"
fontWeight="semibold"
borderRadius={0}
colorScheme="blue"
color="black"
fontSize="sm"
borderBottomWidth={1}
>
<Text>{option as string}</Text>
{option === selectedOption && <Icon as={BiCheck} color="blue.500" boxSize={5} />}
</HStack>
))}
</VStack>
</PopoverContent>
</Popover>
);
};
export default InputDropdown;

View File

@@ -1,20 +1,17 @@
import { useCallback, useState } from "react";
import { HStack, IconButton, Input, Select } from "@chakra-ui/react";
import { HStack, IconButton, Input } from "@chakra-ui/react";
import { BsTrash } from "react-icons/bs";
import { type LogFilter, comparators } from "~/state/logFiltersSlice";
import { type LogFilter } from "~/state/logFiltersSlice";
import { useAppStore } from "~/state/store";
import { useFilterableFields } from "~/utils/hooks";
import { debounce } from "lodash-es";
import SelectFieldDropdown from "./SelectFieldDropdown";
import SelectComparatorDropdown from "./SelectComparatorDropdown";
const LogFilter = ({ filter, index }: { filter: LogFilter; index: number }) => {
const filterableFields = useFilterableFields();
const updateFilter = useAppStore((s) => s.logFilters.updateFilter);
const deleteFilter = useAppStore((s) => s.logFilters.deleteFilter);
const { field, comparator, value } = filter;
const [editedValue, setEditedValue] = useState("");
const debouncedUpdateFilter = useCallback(
@@ -31,31 +28,8 @@ const LogFilter = ({ filter, index }: { filter: LogFilter; index: number }) => {
return (
<HStack>
<Select
value={field}
onChange={(e) => updateFilter(index, { ...filter, field: e.target.value })}
>
{filterableFields.data?.map((field) => (
<option key={field} value={field}>
{field}
</option>
))}
</Select>
<Select
value={comparator}
onChange={(e) =>
updateFilter(index, {
...filter,
comparator: e.target.value as (typeof comparators)[number],
})
}
>
{comparators.map((comparator) => (
<option key={comparator} value={comparator}>
{comparator}
</option>
))}
</Select>
<SelectFieldDropdown filter={filter} index={index} />
<SelectComparatorDropdown filter={filter} index={index} />
<Input
value={editedValue}
onChange={(e) => {

View File

@@ -0,0 +1,20 @@
import { comparators, type LogFilter } from "~/state/logFiltersSlice";
import { useAppStore } from "~/state/store";
import InputDropdown from "~/components/InputDropdown";
const SelectComparatorDropdown = ({ filter, index }: { filter: LogFilter; index: number }) => {
const updateFilter = useAppStore((s) => s.logFilters.updateFilter);
const { comparator } = filter;
return (
<InputDropdown
options={comparators}
selectedOption={comparator}
onSelect={(option) => updateFilter(index, { ...filter, comparator: option })}
inputGroupProps={{ w: 300 }}
/>
);
};
export default SelectComparatorDropdown;

View File

@@ -0,0 +1,22 @@
import { type LogFilter } from "~/state/logFiltersSlice";
import { useAppStore } from "~/state/store";
import { useFilterableFields } from "~/utils/hooks";
import InputDropdown from "~/components/InputDropdown";
const SelectFieldDropdown = ({ filter, index }: { filter: LogFilter; index: number }) => {
const filterableFields = useFilterableFields().data;
const updateFilter = useAppStore((s) => s.logFilters.updateFilter);
const { field } = filter;
return (
<InputDropdown
options={filterableFields || []}
selectedOption={field}
onSelect={(option) => updateFilter(index, { ...filter, field: option })}
/>
);
};
export default SelectFieldDropdown;