mirror of
https://github.com/gosticks/plane.git
synced 2025-10-16 12:45:33 +00:00
[WEB-4684] chore: dialog component enhancements (#7606)
* chore: z-index tokens added * chore: dialog component code refactor * chore: dialog component improvements * fix: lint error * fix: lint error * fix: format error
This commit is contained in:
parent
b8a88fe89c
commit
03479cf6b3
@ -1,17 +0,0 @@
|
|||||||
export enum EDialogPosition {
|
|
||||||
TOP = "flex items-center justify-center text-center mx-4 my-10 md:my-20",
|
|
||||||
CENTER = "flex items-end sm:items-center justify-center p-4 min-h-full",
|
|
||||||
}
|
|
||||||
|
|
||||||
export enum EDialogWidth {
|
|
||||||
SM = "sm:max-w-sm",
|
|
||||||
MD = "sm:max-w-md",
|
|
||||||
LG = "sm:max-w-lg",
|
|
||||||
XL = "sm:max-w-xl",
|
|
||||||
XXL = "sm:max-w-2xl",
|
|
||||||
XXXL = "sm:max-w-3xl",
|
|
||||||
XXXXL = "sm:max-w-4xl",
|
|
||||||
VXL = "sm:max-w-5xl",
|
|
||||||
VIXL = "sm:max-w-6xl",
|
|
||||||
VIIXL = "sm:max-w-7xl",
|
|
||||||
}
|
|
||||||
@ -3,75 +3,116 @@
|
|||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import { Dialog as BaseDialog } from "@base-ui-components/react";
|
import { Dialog as BaseDialog } from "@base-ui-components/react";
|
||||||
import { cn } from "@plane/utils";
|
import { cn } from "@plane/utils";
|
||||||
import { EDialogWidth } from "./constants";
|
|
||||||
|
|
||||||
function DialogPortal({ ...props }: React.ComponentProps<typeof BaseDialog.Portal>) {
|
// enums
|
||||||
return <BaseDialog.Portal data-slot="dialog-portal" {...props} />;
|
|
||||||
|
export enum EDialogWidth {
|
||||||
|
SM = "sm:max-w-sm",
|
||||||
|
MD = "sm:max-w-md",
|
||||||
|
LG = "sm:max-w-lg",
|
||||||
|
XL = "sm:max-w-xl",
|
||||||
|
XXL = "sm:max-w-2xl",
|
||||||
|
XXXL = "sm:max-w-3xl",
|
||||||
|
XXXXL = "sm:max-w-4xl",
|
||||||
|
VXL = "sm:max-w-5xl",
|
||||||
|
VIXL = "sm:max-w-6xl",
|
||||||
|
VIIXL = "sm:max-w-7xl",
|
||||||
}
|
}
|
||||||
|
|
||||||
function DialogOverlay({ className, ...props }: React.ComponentProps<typeof BaseDialog.Backdrop>) {
|
// Types
|
||||||
return (
|
export type DialogPosition = "center" | "top";
|
||||||
<BaseDialog.Backdrop
|
|
||||||
data-slot="dialog-overlay"
|
export interface DialogProps extends React.ComponentProps<typeof BaseDialog.Root> {
|
||||||
className={cn(
|
children: React.ReactNode;
|
||||||
"fixed inset-0 z-30 bg-custom-backdrop transition-all duration-200 [&[data-ending-style]]:opacity-0 [&[data-starting-style]]:opacity-0",
|
|
||||||
className
|
|
||||||
)}
|
|
||||||
{...props}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function Dialog({ ...props }: React.ComponentProps<typeof BaseDialog.Root>) {
|
export interface DialogPanelProps extends React.ComponentProps<typeof BaseDialog.Popup> {
|
||||||
return <BaseDialog.Root data-slot="dialog" {...props} />;
|
width?: EDialogWidth;
|
||||||
|
position?: DialogPosition;
|
||||||
|
children: React.ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
function DialogTrigger({ ...props }: React.ComponentProps<typeof BaseDialog.Trigger>) {
|
export interface DialogTitleProps extends React.ComponentProps<typeof BaseDialog.Title> {
|
||||||
return <BaseDialog.Trigger data-slot="dialog-trigger" {...props} />;
|
children: React.ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
function DialogPanel({
|
// Constants
|
||||||
className,
|
const OVERLAY_CLASSNAME = cn("fixed inset-0 z-backdrop bg-custom-backdrop");
|
||||||
width = EDialogWidth.XXL,
|
const BASE_CLASSNAME = "relative text-left bg-custom-background-100 rounded-lg shadow-md w-full z-modal";
|
||||||
children,
|
|
||||||
...props
|
// Utility functions
|
||||||
}: React.ComponentProps<typeof BaseDialog.Popup> & { width?: EDialogWidth }) {
|
const getPositionClassNames = React.useCallback(
|
||||||
return (
|
(position: DialogPosition) =>
|
||||||
<DialogPortal data-slot="dialog-portal">
|
cn("isolate fixed z-modal", {
|
||||||
<DialogOverlay />
|
"top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2": position === "center",
|
||||||
<BaseDialog.Popup
|
"top-8 left-1/2 -translate-x-1/2": position === "top",
|
||||||
data-slot="dialog-content"
|
}),
|
||||||
className={cn(
|
[]
|
||||||
"fixed flex justify-center top-0 left-0 w-full z-30 px-4 sm:py-20 overflow-y-auto overflow-hidden outline-none"
|
);
|
||||||
)}
|
|
||||||
{...props}
|
const DialogPortal = React.memo<React.ComponentProps<typeof BaseDialog.Portal>>(({ children, ...props }) => (
|
||||||
>
|
<BaseDialog.Portal data-slot="dialog-portal" {...props}>
|
||||||
<div
|
{children}
|
||||||
className={cn(
|
</BaseDialog.Portal>
|
||||||
"rounded-lg bg-custom-background-100 text-left shadow-custom-shadow-md transition-all w-full",
|
));
|
||||||
width,
|
DialogPortal.displayName = "DialogPortal";
|
||||||
className
|
|
||||||
)}
|
const DialogOverlay = React.memo<React.ComponentProps<typeof BaseDialog.Backdrop>>(({ className, ...props }) => (
|
||||||
|
<BaseDialog.Backdrop data-slot="dialog-overlay" className={cn(OVERLAY_CLASSNAME, className)} {...props} />
|
||||||
|
));
|
||||||
|
DialogOverlay.displayName = "DialogOverlay";
|
||||||
|
|
||||||
|
const DialogComponent = React.memo<DialogProps>(({ children, ...props }) => (
|
||||||
|
<BaseDialog.Root data-slot="dialog" {...props}>
|
||||||
|
{children}
|
||||||
|
</BaseDialog.Root>
|
||||||
|
));
|
||||||
|
DialogComponent.displayName = "Dialog";
|
||||||
|
|
||||||
|
const DialogTrigger = React.memo<React.ComponentProps<typeof BaseDialog.Trigger>>(({ children, ...props }) => (
|
||||||
|
<BaseDialog.Trigger data-slot="dialog-trigger" {...props}>
|
||||||
|
{children}
|
||||||
|
</BaseDialog.Trigger>
|
||||||
|
));
|
||||||
|
DialogTrigger.displayName = "DialogTrigger";
|
||||||
|
|
||||||
|
const DialogPanel = React.forwardRef<React.ElementRef<typeof BaseDialog.Popup>, DialogPanelProps>(
|
||||||
|
({ className, width = EDialogWidth.XXL, children, position = "center", ...props }, ref) => {
|
||||||
|
const positionClassNames = React.useMemo(() => getPositionClassNames(position), [position]);
|
||||||
|
return (
|
||||||
|
<DialogPortal>
|
||||||
|
<DialogOverlay />
|
||||||
|
<BaseDialog.Popup
|
||||||
|
ref={ref}
|
||||||
|
data-slot="dialog-content"
|
||||||
|
className={cn(BASE_CLASSNAME, positionClassNames, width, className)}
|
||||||
|
role="dialog"
|
||||||
|
aria-modal="true"
|
||||||
|
{...props}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
</div>
|
</BaseDialog.Popup>
|
||||||
</BaseDialog.Popup>
|
</DialogPortal>
|
||||||
</DialogPortal>
|
);
|
||||||
);
|
}
|
||||||
}
|
);
|
||||||
|
DialogPanel.displayName = "DialogPanel";
|
||||||
|
|
||||||
function DialogTitle({ className, ...props }: React.ComponentProps<typeof BaseDialog.Title>) {
|
const DialogTitle = React.memo<DialogTitleProps>(({ className, children, ...props }) => (
|
||||||
return (
|
<BaseDialog.Title data-slot="dialog-title" className={cn("text-lg leading-none font-semibold", className)} {...props}>
|
||||||
<BaseDialog.Title
|
{children}
|
||||||
data-slot="dialog-title"
|
</BaseDialog.Title>
|
||||||
className={cn("text-lg leading-none font-semibold", className)}
|
));
|
||||||
{...props}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
// compound components
|
|
||||||
Dialog.Trigger = DialogTrigger;
|
|
||||||
Dialog.Panel = DialogPanel;
|
|
||||||
Dialog.Title = DialogTitle;
|
|
||||||
|
|
||||||
export { Dialog, DialogTitle, DialogTrigger, DialogPanel };
|
DialogTitle.displayName = "DialogTitle";
|
||||||
|
|
||||||
|
// Create the compound Dialog component with proper typing
|
||||||
|
const Dialog = Object.assign(DialogComponent, {
|
||||||
|
Panel: DialogPanel,
|
||||||
|
Title: DialogTitle,
|
||||||
|
}) as typeof DialogComponent & {
|
||||||
|
Panel: typeof DialogPanel;
|
||||||
|
Title: typeof DialogTitle;
|
||||||
|
};
|
||||||
|
|
||||||
|
export { Dialog, DialogTitle, DialogPanel };
|
||||||
|
|||||||
@ -97,9 +97,11 @@ const PopoverPortal = React.memo<React.ComponentProps<typeof BasePopover.Portal>
|
|||||||
return <BasePopover.Portal data-slot="popover-portal" {...props} />;
|
return <BasePopover.Portal data-slot="popover-portal" {...props} />;
|
||||||
});
|
});
|
||||||
|
|
||||||
const PopoverPositioner = React.memo<React.ComponentProps<typeof BasePopover.Positioner>>(function PopoverPositioner(props) {
|
const PopoverPositioner = React.memo<React.ComponentProps<typeof BasePopover.Positioner>>(
|
||||||
return <BasePopover.Positioner data-slot="popover-positioner" {...props} />;
|
function PopoverPositioner(props) {
|
||||||
});
|
return <BasePopover.Positioner data-slot="popover-positioner" {...props} />;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
// compound components
|
// compound components
|
||||||
const Popover = Object.assign(
|
const Popover = Object.assign(
|
||||||
@ -119,4 +121,4 @@ PopoverPortal.displayName = "PopoverPortal";
|
|||||||
PopoverTrigger.displayName = "PopoverTrigger";
|
PopoverTrigger.displayName = "PopoverTrigger";
|
||||||
PopoverPositioner.displayName = "PopoverPositioner";
|
PopoverPositioner.displayName = "PopoverPositioner";
|
||||||
|
|
||||||
export { Popover};
|
export { Popover };
|
||||||
|
|||||||
@ -442,6 +442,20 @@ module.exports = {
|
|||||||
fontFamily: {
|
fontFamily: {
|
||||||
custom: ["Inter", "sans-serif"],
|
custom: ["Inter", "sans-serif"],
|
||||||
},
|
},
|
||||||
|
zIndex: {
|
||||||
|
base: 0 /* default content */,
|
||||||
|
header: 10 /* sticky headers, navbars */,
|
||||||
|
sidebar: 20 /* sidebars, drawers */,
|
||||||
|
dropdown: 30 /* dropdowns, select menus */,
|
||||||
|
popover: 40 /* popovers, hovercards */,
|
||||||
|
tooltip: 50 /* tooltips, hints */,
|
||||||
|
sticky: 60 /* sticky UI */,
|
||||||
|
backdrop: 90 /* backdrop / overlay */,
|
||||||
|
modal: 100 /* dialogs, modals */,
|
||||||
|
toast: 110 /* toast, alerts */,
|
||||||
|
loader: 120 /* blocking loader/spinner */,
|
||||||
|
max: 9999 /* emergency override (rare use) */,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user