Feat: make text input capable of support dropdown inputs also

This commit is contained in:
igorrCarvalho 2024-02-05 11:42:08 -03:00
commit 86ccae87fb
3 changed files with 142 additions and 30 deletions

View file

@ -1,8 +1,10 @@
import { Listbox, Transition } from "@headlessui/react";
import * as Form from "@radix-ui/react-form"; import * as Form from "@radix-ui/react-form";
import { useEffect, useRef, useState } from "react"; import { Fragment, useEffect, useRef, useState } from "react";
import { InputComponentType } from "../../types/components"; import { InputComponentType } from "../../types/components";
import { handleKeyDown } from "../../utils/reactflowUtils"; import { handleKeyDown } from "../../utils/reactflowUtils";
import { classNames } from "../../utils/utils"; import { classNames } from "../../utils/utils";
import IconComponent from "../genericIconComponent";
import { Input } from "../ui/input"; import { Input } from "../ui/input";
export default function InputComponent({ export default function InputComponent({
@ -19,9 +21,11 @@ export default function InputComponent({
className, className,
id = "", id = "",
blurOnEnter = false, blurOnEnter = false,
options = [],
}: InputComponentType): JSX.Element { }: InputComponentType): JSX.Element {
const [pwdVisible, setPwdVisible] = useState(false); const [pwdVisible, setPwdVisible] = useState(false);
const refInput = useRef<HTMLInputElement>(null); const refInput = useRef<HTMLInputElement>(null);
const [showOptions, setShowOptions] = useState<boolean>(false);
// Clear component state // Clear component state
useEffect(() => { useEffect(() => {
if (disabled && value !== "") { if (disabled && value !== "") {
@ -29,6 +33,11 @@ export default function InputComponent({
} }
}, [disabled]); }, [disabled]);
function onInputLostFocus(event): void {
if (onBlur) onBlur(event);
setShowOptions(false);
}
return ( return (
<div className="relative w-full"> <div className="relative w-full">
{isForm ? ( {isForm ? (
@ -36,7 +45,7 @@ export default function InputComponent({
<Input <Input
id={"form-" + id} id={"form-" + id}
ref={refInput} ref={refInput}
onBlur={onBlur} onBlur={onInputLostFocus}
autoFocus={autoFocus} autoFocus={autoFocus}
type={password && !pwdVisible ? "password" : "text"} type={password && !pwdVisible ? "password" : "text"}
value={value} value={value}
@ -65,34 +74,136 @@ export default function InputComponent({
/> />
</Form.Control> </Form.Control>
) : ( ) : (
<Input <>
id={id} <Input
ref={refInput} id={id}
type="text" ref={refInput}
onBlur={onBlur} type="text"
value={value} onBlur={(e) => setShowOptions(false)}
autoFocus={autoFocus} value={value}
disabled={disabled} autoFocus={autoFocus}
required={required} disabled={disabled}
className={classNames( required={required}
password && !pwdVisible && value !== "" className={classNames(
? " text-clip password " password && !pwdVisible && value !== ""
: "", ? " text-clip password "
editNode ? " input-edit-node " : "", : "",
password && editNode ? "pr-8" : "", editNode ? " input-edit-node " : "",
password && !editNode ? "pr-10" : "", password && editNode ? "pr-8" : "",
className! password && !editNode ? "pr-10" : "",
)} className!
placeholder={password && editNode ? "Key" : placeholder} )}
onChange={(e) => { placeholder={password && editNode ? "Key" : placeholder}
onChange(e.target.value); onChange={(e) => {
}} onChange(e.target.value);
onKeyDown={(e) => { setShowOptions(false);
handleKeyDown(e, value, ""); }}
if (blurOnEnter && e.key === "Enter") refInput.current?.blur(); onKeyDown={(e) => {
}} handleKeyDown(e, value, "");
/> if (blurOnEnter && e.key === "Enter") refInput.current?.blur();
}}
onFocus={() => setShowOptions(true)}
/>
{
/* options.length > 0 */ true ? (
<Listbox
onChange={(val) => {
onChange(val);
}}
>
<>
<div className={"relative mt-1"}>
<Transition
show={showOptions}
as={Fragment}
leave="transition ease-in duration-100"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<Listbox.Options
className={classNames(
editNode
? "dropdown-component-true-options nowheel custom-scroll"
: "dropdown-component-false-options nowheel custom-scroll",
false ? "mb-2 w-[250px]" : "absolute w-full"
)}
>
{["key", "key2", "key3", "key4", "key5"].map(
(option, id) => (
<Listbox.Option
key={id}
className={({ active }) =>
classNames(
active ? " bg-accent" : "",
editNode
? "dropdown-component-false-option"
: "dropdown-component-true-option",
" hover:bg-accent"
)
}
value={option}
>
{({ selected, active }) => (
<>
<span
className={classNames(
selected
? "font-semibold"
: "font-normal",
"block truncate "
)}
data-testid={`${option}-${id ?? ""}-option`}
>
{option}
</span>
{selected ? (
<span
className={classNames(
active ? "text-background " : "",
"dropdown-component-choosal"
)}
>
<IconComponent
name="Check"
className={
active
? "dropdown-component-check-icon"
: "dropdown-component-check-icon"
}
aria-hidden="true"
/>
</span>
) : null}
</>
)}
</Listbox.Option>
)
)}
</Listbox.Options>
</Transition>
</div>
</>
</Listbox>
) : null
}
</>
)} )}
<span
className={
password
? "dropdown-component-arrow right-8"
: "dropdown-component-arrow right-0"
}
>
<IconComponent
name="ChevronsUpDown"
className="dropdown-component-arrow-color"
aria-hidden="true"
/>
</span>
{password && ( {password && (
<button <button
type="button" type="button"

View file

@ -422,7 +422,7 @@
@apply block w-full truncate bg-background; @apply block w-full truncate bg-background;
} }
.dropdown-component-arrow { .dropdown-component-arrow {
@apply pointer-events-none absolute inset-y-0 right-0 flex items-center pr-2; @apply pointer-events-none absolute inset-y-0 flex items-center pr-2;
} }
.dropdown-component-arrow-color { .dropdown-component-arrow-color {
@apply extra-side-bar-save-disable h-5 w-5; @apply extra-side-bar-save-disable h-5 w-5;

View file

@ -20,6 +20,7 @@ export type InputComponentType = {
className?: string; className?: string;
id?: string; id?: string;
blurOnEnter?: boolean; blurOnEnter?: boolean;
options?: string[];
}; };
export type ToggleComponentType = { export type ToggleComponentType = {
enabled: boolean; enabled: boolean;