feat: add custom value on dropown ui (#2961)
* Added fuzzy search and custom value on search on Dropdown Component * added allowCustom prop to allow custom values on dropdownComponent * changed type of allowCustom * added custom to custom field on dropdown * Fixed empty search not showing all of the options * Added Text on the left of the label
This commit is contained in:
parent
02a879f330
commit
6a482f36c4
4 changed files with 67 additions and 8 deletions
10
src/frontend/package-lock.json
generated
10
src/frontend/package-lock.json
generated
|
|
@ -48,6 +48,7 @@
|
|||
"esbuild": "^0.21.5",
|
||||
"file-saver": "^2.0.5",
|
||||
"framer-motion": "^11.2.10",
|
||||
"fuse.js": "^7.0.0",
|
||||
"lodash": "^4.17.21",
|
||||
"lucide-react": "^0.395.0",
|
||||
"million": "^3.1.11",
|
||||
|
|
@ -7804,6 +7805,15 @@
|
|||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/fuse.js": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fuse.js/-/fuse.js-7.0.0.tgz",
|
||||
"integrity": "sha512-14F4hBIxqKvD4Zz/XjDc3y94mNZN6pRv3U13Udo0lNLCWRBUsrMv2xwcF/y/Z5sV6+FQW+/ow68cHpm4sunt8Q==",
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/gauge": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz",
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@
|
|||
"esbuild": "^0.21.5",
|
||||
"file-saver": "^2.0.5",
|
||||
"framer-motion": "^11.2.10",
|
||||
"fuse.js": "^7.0.0",
|
||||
"lodash": "^4.17.21",
|
||||
"lucide-react": "^0.395.0",
|
||||
"million": "^3.1.11",
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
import { PopoverAnchor } from "@radix-ui/react-popover";
|
||||
import { useRef, useState } from "react";
|
||||
import Fuse from "fuse.js";
|
||||
import { cloneDeep } from "lodash";
|
||||
import { ChangeEvent, useEffect, useRef, useState } from "react";
|
||||
import { DropDownComponentType } from "../../types/components";
|
||||
import { cn } from "../../utils/utils";
|
||||
import { default as ForwardedIconComponent } from "../genericIconComponent";
|
||||
|
|
@ -8,7 +10,6 @@ import {
|
|||
Command,
|
||||
CommandEmpty,
|
||||
CommandGroup,
|
||||
CommandInput,
|
||||
CommandItem,
|
||||
CommandList,
|
||||
} from "../ui/command";
|
||||
|
|
@ -24,6 +25,7 @@ export default function Dropdown({
|
|||
isLoading,
|
||||
value,
|
||||
options,
|
||||
combobox = true,
|
||||
onSelect,
|
||||
editNode = false,
|
||||
id = "",
|
||||
|
|
@ -35,6 +37,31 @@ export default function Dropdown({
|
|||
|
||||
const PopoverContentDropdown =
|
||||
children || editNode ? PopoverContent : PopoverContentWithoutPortal;
|
||||
|
||||
const [customValue, setCustomValue] = useState("");
|
||||
const [filteredOptions, setFilteredOptions] = useState(options);
|
||||
|
||||
const fuse = new Fuse(options, { keys: ["name", "value"] });
|
||||
|
||||
const searchRoleByTerm = async (event: ChangeEvent<HTMLInputElement>) => {
|
||||
const value = event.target.value;
|
||||
const searchValues = fuse.search(value);
|
||||
const filtered = searchValues.map((search) => search.item);
|
||||
if (!filtered.includes(value) && combobox) filtered.push(value);
|
||||
setFilteredOptions(value ? filtered : options);
|
||||
setCustomValue(value);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (open) {
|
||||
const filtered = cloneDeep(options);
|
||||
if (customValue === value && combobox) {
|
||||
filtered.push(customValue);
|
||||
}
|
||||
setFilteredOptions(filtered);
|
||||
}
|
||||
}, [open]);
|
||||
|
||||
return (
|
||||
<>
|
||||
{Object.keys(options ?? [])?.length > 0 ? (
|
||||
|
|
@ -60,11 +87,14 @@ export default function Dropdown({
|
|||
editNode ? "input-edit-node" : "py-2",
|
||||
)}
|
||||
>
|
||||
<span data-testid={`value-dropdown-` + id}>
|
||||
<span
|
||||
className="truncate"
|
||||
data-testid={`value-dropdown-` + id}
|
||||
>
|
||||
{value &&
|
||||
value !== "" &&
|
||||
options.find((option) => option === value)
|
||||
? options.find((option) => option === value)
|
||||
filteredOptions.find((option) => option === value)
|
||||
? filteredOptions.find((option) => option === value)
|
||||
: "Choose an option..."}
|
||||
</span>
|
||||
|
||||
|
|
@ -86,11 +116,21 @@ export default function Dropdown({
|
|||
}
|
||||
>
|
||||
<Command>
|
||||
<CommandInput placeholder="Search options..." className="h-9" />
|
||||
<div className="flex items-center border-b px-3">
|
||||
<ForwardedIconComponent
|
||||
name="search"
|
||||
className="mr-2 h-4 w-4 shrink-0 opacity-50"
|
||||
/>
|
||||
<input
|
||||
onChange={searchRoleByTerm}
|
||||
placeholder="Search options..."
|
||||
className="flex h-9 w-full rounded-md bg-transparent py-3 text-sm outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50"
|
||||
/>
|
||||
</div>
|
||||
<CommandList>
|
||||
<CommandEmpty>No values found.</CommandEmpty>
|
||||
<CommandGroup defaultChecked={false}>
|
||||
{options?.map((option, id) => (
|
||||
{filteredOptions?.map((option, id) => (
|
||||
<CommandItem
|
||||
key={id}
|
||||
value={option}
|
||||
|
|
@ -98,8 +138,16 @@ export default function Dropdown({
|
|||
onSelect(currentValue);
|
||||
setOpen(false);
|
||||
}}
|
||||
className="items-center truncate"
|
||||
data-testid={`${option}-${id ?? ""}-option`}
|
||||
>
|
||||
{customValue === option ? (
|
||||
<span className="text-muted-foreground">
|
||||
Text:
|
||||
</span>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
{option}
|
||||
<ForwardedIconComponent
|
||||
name="Check"
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
import { ColDef } from "ag-grid-community";
|
||||
import { ReactElement, ReactNode, SetStateAction } from "react";
|
||||
import { ReactFlowJsonObject } from "reactflow";
|
||||
import { InputOutput } from "../../constants/enums";
|
||||
|
|
@ -54,6 +53,7 @@ export type DropDownComponentType = {
|
|||
disabled?: boolean;
|
||||
isLoading?: boolean;
|
||||
value: string;
|
||||
combobox?: boolean;
|
||||
options: string[];
|
||||
onSelect: (value: string) => void;
|
||||
editNode?: boolean;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue