keycloak-scim/js/libs/ui-shared/src/controls/SelectControl.tsx

121 lines
3.1 KiB
TypeScript
Raw Normal View History

2023-01-16 10:23:07 +00:00
import { useState } from "react";
import {
Controller,
ControllerProps,
FieldValues,
FieldPath,
useFormContext,
UseControllerProps,
} from "react-hook-form";
import {
Select,
SelectOption,
SelectProps,
SelectVariant,
2023-01-16 10:23:07 +00:00
ValidatedOptions,
} from "@patternfly/react-core";
import { FormLabel } from "./FormLabel";
2023-01-16 10:23:07 +00:00
2023-07-06 07:33:28 +00:00
export type SelectControlOption = {
2023-01-16 10:23:07 +00:00
key: string;
value: string;
};
export type SelectControlProps<
2023-01-16 10:23:07 +00:00
T extends FieldValues,
P extends FieldPath<T> = FieldPath<T>,
2023-01-16 10:23:07 +00:00
> = Omit<
SelectProps,
"name" | "onToggle" | "selections" | "onSelect" | "onClear" | "isOpen"
> &
UseControllerProps<T, P> & {
name: string;
label?: string;
2023-07-06 07:33:28 +00:00
options: string[] | SelectControlOption[];
labelIcon?: string;
2023-01-16 10:23:07 +00:00
controller: Omit<ControllerProps, "name" | "render">;
};
export const SelectControl = <
T extends FieldValues,
P extends FieldPath<T> = FieldPath<T>,
2023-01-16 10:23:07 +00:00
>({
name,
label,
options,
controller,
variant,
labelIcon,
2023-01-16 10:23:07 +00:00
...rest
}: SelectControlProps<T, P>) => {
const {
control,
formState: { errors },
} = useFormContext();
const [open, setOpen] = useState(false);
return (
<FormLabel
name={name}
label={label}
2023-01-16 10:23:07 +00:00
isRequired={controller.rules?.required === true}
error={errors[name]}
labelIcon={labelIcon}
2023-01-16 10:23:07 +00:00
>
<Controller
{...controller}
name={name}
control={control}
render={({ field: { onChange, value } }) => (
<Select
{...rest}
toggleId={name.slice(name.lastIndexOf(".") + 1)}
2023-01-16 10:23:07 +00:00
onToggle={(isOpen) => setOpen(isOpen)}
selections={
typeof options[0] !== "string"
? (options as SelectControlOption[])
.filter((o) => value.includes(o.key))
.map((o) => o.value)
: value
}
2023-01-16 10:23:07 +00:00
onSelect={(_, v) => {
if (variant === "typeaheadmulti") {
const option = v.toString();
if (value.includes(option)) {
onChange(value.filter((item: string) => item !== option));
} else {
onChange([...value, option]);
}
2023-01-16 10:23:07 +00:00
} else {
onChange(v);
setOpen(false);
2023-01-16 10:23:07 +00:00
}
}}
onClear={
variant !== SelectVariant.single
? (event) => {
event.stopPropagation();
onChange([]);
}
: undefined
}
2023-01-16 10:23:07 +00:00
isOpen={open}
variant={variant}
2023-01-16 10:23:07 +00:00
validated={
errors[name] ? ValidatedOptions.error : ValidatedOptions.default
}
>
{options.map((option) => (
<SelectOption
key={typeof option === "string" ? option : option.key}
value={typeof option === "string" ? option : option.key}
>
{typeof option === "string" ? option : option.value}
</SelectOption>
))}
</Select>
)}
/>
</FormLabel>
2023-01-16 10:23:07 +00:00
);
};