Select Git revision
baseComponents.tsx
Klaas Kliffen authored
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
baseComponents.tsx 3.61 KiB
import { Input } from "@nextui-org/react";
import { Dispatch, ReactNode, SetStateAction } from "react";
import { InputSlots } from "@nextui-org/theme";
import { clsx } from "clsx";
import Typography from "src/components/Typography.tsx";
import { formFieldBg, cursorPointer } from "./classes.ts";
export type LabelPlacement = "outside" | "outside-left";
type BaseInputProps = {
// basic info
name?: string; // allow for FormData to work
label: string;
labelPlacement: LabelPlacement;
labelClass: string;
labelCustomColor: boolean;
endContent: ReactNode; // such as units or icon
// value and validation
placeholder: string;
isClearable?: boolean;
value?: string;
onValueChange?: Dispatch<SetStateAction<string>>;
isInvalid: boolean;
errorMessage: string;
maxLength?: number;
type?:
| "text"
| "search"
| "url"
| "tel"
| "email"
| "password"
| (string & NonNullable<unknown>);
// interaction
isRequired?: boolean;
isDisabled?: boolean;
isReadOnly?: boolean;
inputMode?:
| "none"
| "text"
| "tel"
| "url"
| "email"
| "numeric"
| "decimal"
| "search";
};
type baseInputClassNamesObj = { [key in InputSlots]: string };
export const baseInputClassNames = (
isDisabled: boolean,
labelPlacement: LabelPlacement
): baseInputClassNamesObj => {
// this is the border color (use text-*)
const mainWrapperClass = (isDisabled: boolean) =>
isDisabled
? "text-mediumGrey dark:text-darkModeBlue"
: "text-grey dark:text-mediumGrey hover:text-baseBlack focus-within:!text-primary";
const clearButtonClass = (isDisabled: boolean) => {
if (isDisabled) return "";
// we cannot do "[&>svg]:" + className because Tailwind does not support dynamic class names
const clearButtonSvgClass: string =
"[&>svg]:w-[30px] [&>svg]:h-[30px] [&>svg]:mt-[-4px] [&>svg]:ml-[-4px]";
const clearButtonBaseClass: string =
"bg-mediumGrey text-baseWhite dark:bg-baseWhite dark:text-mediumGrey w-[22px] h-[22px] p-0 !opacity-100";
return clsx(clearButtonSvgClass, clearButtonBaseClass);
};
return {
base: clsx("flex flex-row justify-between", cursorPointer(isDisabled)),
input: "!text-foreground-body bg-default",
inputWrapper: clsx(
"px-2 rounded-[4px] min-h-[33px] max-h-[33px]",
formFieldBg(isDisabled)
),
mainWrapper: clsx(
{
"w-2/3": labelPlacement === "outside-left",
},
mainWrapperClass(isDisabled)
),
clearButton: clearButtonClass(isDisabled),
} as baseInputClassNamesObj;
};
export const BaseInput = ({
name,
label,
labelPlacement = "outside",
labelClass,
labelCustomColor,
endContent,
placeholder,
isClearable = false,
value,
onValueChange,
isInvalid,
errorMessage,
maxLength,
type = "text",
isRequired = false,
isDisabled = false,
isReadOnly = false,
inputMode = "text",
}: BaseInputProps) => {
return (
<Input
label={
<Typography
text={label}
variant="paragraph"
customClass={labelClass}
customColor={labelCustomColor}
/>
}
name={name}
endContent={endContent}
placeholder={placeholder}
value={value}
isClearable={isClearable}
onValueChange={onValueChange}
isInvalid={isInvalid}
errorMessage={errorMessage}
maxLength={maxLength}
type={type}
isRequired={isRequired}
isDisabled={isDisabled}
isReadOnly={isReadOnly}
inputMode={inputMode}
// appearance
labelPlacement={labelPlacement}
variant="bordered"
classNames={baseInputClassNames(isDisabled, labelPlacement)}
/>
);
};