Add policies version history
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
abe0ce1dde
commit
2e6741942b
@@ -8,63 +8,100 @@ import {
|
||||
Close,
|
||||
} from "@radix-ui/react-dialog";
|
||||
import { IconCrossLargeX } from "../../Atoms/Icons";
|
||||
import { type HTMLAttributes, type ReactNode } from "react";
|
||||
import {
|
||||
Children,
|
||||
cloneElement,
|
||||
isValidElement,
|
||||
useRef,
|
||||
useState,
|
||||
type ComponentProps,
|
||||
type CSSProperties,
|
||||
type HTMLAttributes,
|
||||
type ReactElement,
|
||||
type ReactNode,
|
||||
type RefObject,
|
||||
} from "react";
|
||||
import { Button } from "../../Atoms/Button/Button";
|
||||
import { useTranslate } from "@probo/i18n";
|
||||
import clsx from "clsx";
|
||||
import { tv } from "tailwind-variants";
|
||||
|
||||
export const dialog = tv({
|
||||
slots: {
|
||||
overlay:
|
||||
"fixed inset-0 z-50 bg-dialog/40 duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
|
||||
content:
|
||||
"text-txt-secondary text-sm fixed inset-0 m-auto z-50 w-full h-max bg-level-2 rounded-2xl max-w-5xl w-[95%] duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-top-5 data-[state=open]:slide-in-from-top-5",
|
||||
header: "flex justify-between items-center p-3 border-b border-b-border-low",
|
||||
title: "text-sm font-medium text-txt-primary",
|
||||
footer: "flex justify-end items-center p-3 border-t border-t-border-low gap-2",
|
||||
},
|
||||
});
|
||||
|
||||
type Props = {
|
||||
trigger?: ReactNode;
|
||||
title: ReactNode;
|
||||
title?: ReactNode;
|
||||
children?: ReactNode;
|
||||
onOpenChange?: (open: boolean) => void;
|
||||
open?: boolean;
|
||||
defaultOpen?: boolean;
|
||||
className?: string;
|
||||
ref?: RefObject<{ open: () => void; close: () => void } | null>;
|
||||
};
|
||||
|
||||
export const useDialogRef = () => {
|
||||
return useRef<{ open: () => void; close: () => void } | null>(null);
|
||||
};
|
||||
|
||||
export function Dialog({
|
||||
trigger,
|
||||
title,
|
||||
children,
|
||||
onOpenChange,
|
||||
open,
|
||||
className,
|
||||
ref,
|
||||
defaultOpen,
|
||||
}: Props) {
|
||||
const { overlay, content, header, title: titleClassname } = dialog();
|
||||
const [open, setOpen] = useState(!!defaultOpen);
|
||||
|
||||
if (ref) {
|
||||
ref.current = {
|
||||
open() {
|
||||
setOpen(true);
|
||||
},
|
||||
close() {
|
||||
setOpen(false);
|
||||
},
|
||||
};
|
||||
}
|
||||
return (
|
||||
<Root open={open} onOpenChange={onOpenChange}>
|
||||
<Root open={open} onOpenChange={setOpen}>
|
||||
{trigger && <Trigger asChild>{trigger}</Trigger>}
|
||||
<Portal>
|
||||
<Overlay
|
||||
className={clsx(
|
||||
"fixed inset-0 z-50 bg-dialog/40",
|
||||
`duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0`,
|
||||
)}
|
||||
/>
|
||||
<Overlay className={overlay()} />
|
||||
<Content
|
||||
aria-describedby={undefined}
|
||||
className={clsx(
|
||||
"fixed inset-0 m-auto z-50 w-full h-max bg-level-2 rounded-2xl max-w-5xl w-[95%]",
|
||||
className,
|
||||
`duration-200
|
||||
data-[state=open]:animate-in data-[state=closed]:animate-out
|
||||
data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0
|
||||
data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95
|
||||
data-[state=closed]:slide-out-to-top-5
|
||||
data-[state=open]:slide-in-from-top-5`,
|
||||
)}
|
||||
className={content({ className })}
|
||||
>
|
||||
<div className="flex justify-between items-center p-3 border-b border-b-border-low">
|
||||
<Title className="text-sm font-medium text-txt-primary">
|
||||
{title}
|
||||
</Title>
|
||||
{title ? (
|
||||
<div className={header()}>
|
||||
<Title className={titleClassname()}> {title}</Title>
|
||||
<Close asChild>
|
||||
<Button
|
||||
tabIndex={-1}
|
||||
variant="tertiary"
|
||||
icon={IconCrossLargeX}
|
||||
/>
|
||||
</Close>
|
||||
</div>
|
||||
) : (
|
||||
<Close asChild>
|
||||
<Button
|
||||
tabIndex={-1}
|
||||
variant="tertiary"
|
||||
className="absolute top-4 right-4"
|
||||
icon={IconCrossLargeX}
|
||||
/>
|
||||
</Close>
|
||||
</div>
|
||||
)}
|
||||
{children}
|
||||
</Content>
|
||||
</Portal>
|
||||
@@ -80,8 +117,9 @@ export function DialogFooter({
|
||||
exitLabel?: string;
|
||||
}) {
|
||||
const { __ } = useTranslate();
|
||||
const { footer } = dialog();
|
||||
return (
|
||||
<footer className="flex justify-end items-center p-3 border-t border-t-border-low gap-2">
|
||||
<footer className={footer()}>
|
||||
<Close asChild>
|
||||
<Button variant="secondary">{exitLabel ?? __("Cancel")}</Button>
|
||||
</Close>
|
||||
@@ -91,19 +129,51 @@ export function DialogFooter({
|
||||
}
|
||||
|
||||
export function DialogContent(
|
||||
props: HTMLAttributes<HTMLDivElement> & { padded?: boolean },
|
||||
props: HTMLAttributes<HTMLDivElement> & {
|
||||
padded?: boolean;
|
||||
scrollableChildren?: boolean;
|
||||
},
|
||||
) {
|
||||
let children = props.children;
|
||||
if (props.scrollableChildren) {
|
||||
children = Children.map(props.children, (c) => {
|
||||
if (
|
||||
isValidElement<{
|
||||
className?: string;
|
||||
style?: CSSProperties;
|
||||
}>(c)
|
||||
) {
|
||||
return cloneElement(c, {
|
||||
...c.props,
|
||||
className: clsx(c.props.className, "overflow-y-auto"),
|
||||
style: {
|
||||
maxHeight: "var(--maxHeight)",
|
||||
...c.props.style,
|
||||
},
|
||||
});
|
||||
}
|
||||
return c;
|
||||
});
|
||||
}
|
||||
return (
|
||||
<div
|
||||
{...props}
|
||||
children={children}
|
||||
className={clsx(
|
||||
"overflow-y-auto",
|
||||
props.className,
|
||||
props.padded && "p-6",
|
||||
)}
|
||||
style={{
|
||||
maxHeight: "min(640px, calc(100vh - 140px))",
|
||||
}}
|
||||
style={
|
||||
{
|
||||
"--maxHeight": "min(640px, calc(100vh - 140px))",
|
||||
maxHeight: "var(--maxHeight)",
|
||||
} as CSSProperties
|
||||
}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export function DialogTitle(props: ComponentProps<typeof Title>) {
|
||||
return <Title {...props} />;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user