Add risk creation form
Signed-off-by: Bryan Frimin <bryan@getprobo.com> Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
This commit is contained in:
committed by
Sacha Al Himdani
parent
15cf471454
commit
3d4ecf5f8f
@@ -13,51 +13,116 @@ import * as ScrollArea from "@radix-ui/react-scroll-area";
|
||||
import { input } from "../Input/Input.tsx";
|
||||
import { IconChevronGrabberVertical } from "../Icons/IconChevronGrabberVertical.tsx";
|
||||
import { tv } from "tailwind-variants";
|
||||
import type { ComponentProps, PropsWithChildren } from "react";
|
||||
import {
|
||||
Children,
|
||||
isValidElement,
|
||||
type ComponentProps,
|
||||
type PropsWithChildren,
|
||||
type ReactNode,
|
||||
} from "react";
|
||||
|
||||
type Props = PropsWithChildren<
|
||||
{
|
||||
id?: string;
|
||||
placeholder?: string;
|
||||
onChange?: (s: string) => void;
|
||||
empty?: boolean;
|
||||
} & Omit<ComponentProps<typeof Trigger>, "onChange">
|
||||
onValueChange?: (s: string) => void;
|
||||
variant?: "default" | "editor" | "dashed";
|
||||
invalid?: boolean;
|
||||
disabled?: boolean;
|
||||
} & Omit<ComponentProps<typeof Root>, "onChange">
|
||||
>;
|
||||
|
||||
const select = tv({
|
||||
slots: {
|
||||
trigger: input({
|
||||
className:
|
||||
"flex justify-between items-center gap-4 data-placeholder:text-txt-tertiary w-full whitespace-nowrap",
|
||||
}),
|
||||
trigger:
|
||||
"flex justify-between items-center data-placeholder:text-txt-tertiary whitespace-nowrap cursor-pointer",
|
||||
content:
|
||||
"z-100 shadow-mid rounded-[10px] bg-level-1 p-1 animate-in fade-in slide-in-from-top-2 overflow-y-auto overflow-y-auto",
|
||||
option: "flex items-center gap-2 h-8 text-sm font-medium text-txt-primary hover:bg-tertiary-hover active:bg-tertiary-pressed cursor-pointer px-[10px]",
|
||||
option: "flex items-center h-8 text-sm font-medium text-txt-primary hover:bg-tertiary-hover active:bg-tertiary-pressed cursor-pointer px-[10px]",
|
||||
icon: "-mr-1",
|
||||
},
|
||||
variants: {
|
||||
empty: {
|
||||
invalid: {
|
||||
true: {
|
||||
trigger: "border-dashed pointer-events-none",
|
||||
trigger: "border-border-danger",
|
||||
},
|
||||
},
|
||||
variant: {
|
||||
dashed: {
|
||||
trigger: input({
|
||||
class: "w-full gap-4 border-dashed pointer-events-none",
|
||||
}),
|
||||
},
|
||||
editor: {
|
||||
trigger:
|
||||
"bg-highlight hover:bg-highlight-hover active:bg-highlight-pressed text-txt-primary text-sm px-[10px] py-[6px] rounded-lg w-max gap-2",
|
||||
},
|
||||
default: {
|
||||
trigger: input({ class: "w-full gap-4 " }),
|
||||
},
|
||||
},
|
||||
},
|
||||
compoundVariants: [
|
||||
{
|
||||
invalid: true,
|
||||
variant: "default",
|
||||
class: {
|
||||
trigger: "border-border-danger",
|
||||
},
|
||||
},
|
||||
],
|
||||
defaultVariants: {
|
||||
variant: "default",
|
||||
},
|
||||
});
|
||||
|
||||
const { trigger, option, content } = select();
|
||||
const { trigger, option, content, icon } = select();
|
||||
|
||||
/**
|
||||
* To display the selected value we need to find the selected option among children
|
||||
*/
|
||||
const findSelectedOption = (
|
||||
children: unknown[],
|
||||
condition: (c: { props: Record<string, unknown> }) => boolean,
|
||||
): ReactNode => {
|
||||
const selectedOptions = children.find(
|
||||
// @ts-expect-error We know that the children are ReactElements with props
|
||||
(c) => isValidElement(c) && condition(c),
|
||||
);
|
||||
if (!isValidElement(selectedOptions)) {
|
||||
return null;
|
||||
}
|
||||
return (selectedOptions.props as { children: ReactNode }).children;
|
||||
};
|
||||
|
||||
export function Select({
|
||||
placeholder,
|
||||
children,
|
||||
onChange,
|
||||
empty,
|
||||
onValueChange,
|
||||
value,
|
||||
...props
|
||||
}: Props) {
|
||||
const childrenArr = Children.toArray(children);
|
||||
const valueNode = value
|
||||
? findSelectedOption(
|
||||
childrenArr,
|
||||
(c) => c.props.value?.toString() === value?.toString(),
|
||||
)
|
||||
: undefined;
|
||||
|
||||
return (
|
||||
<Root onValueChange={onChange}>
|
||||
<Trigger className={trigger({ ...props, empty })}>
|
||||
<Root onValueChange={onValueChange} value={value}>
|
||||
<Trigger className={trigger({ ...props })} {...props}>
|
||||
<div className="text-ellipsis overflow-hidden">
|
||||
<Value placeholder={placeholder} />
|
||||
<Value placeholder={placeholder}>
|
||||
{valueNode ? (
|
||||
<span className="flex items-center gap-2">
|
||||
{valueNode}
|
||||
</span>
|
||||
) : null}
|
||||
</Value>
|
||||
</div>
|
||||
<Icon className="SelectIcon">
|
||||
<Icon className={icon()}>
|
||||
<IconChevronGrabberVertical size={16} />
|
||||
</Icon>
|
||||
</Trigger>
|
||||
@@ -88,7 +153,9 @@ export function Select({
|
||||
export function Option({ children, ...props }: ComponentProps<typeof Item>) {
|
||||
return (
|
||||
<Item {...props} className={option(props)}>
|
||||
<ItemText>{children}</ItemText>
|
||||
<ItemText asChild>
|
||||
<span className="flex items-center gap-2">{children}</span>
|
||||
</ItemText>
|
||||
</Item>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user