mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-12-17 00:40:14 +01:00
ℹ️ feat: Dismissible Tooltips in Modals (#10851)
This commit is contained in:
parent
d08f7c2c8a
commit
2ed2b87c30
1 changed files with 65 additions and 22 deletions
|
|
@ -66,28 +66,71 @@ type DialogContentProps = React.ComponentPropsWithoutRef<typeof DialogPrimitive.
|
||||||
const DialogContent = React.forwardRef<
|
const DialogContent = React.forwardRef<
|
||||||
React.ElementRef<typeof DialogPrimitive.Content>,
|
React.ElementRef<typeof DialogPrimitive.Content>,
|
||||||
DialogContentProps
|
DialogContentProps
|
||||||
>(({ className, overlayClassName, showCloseButton = true, children, ...props }, ref) => (
|
>(
|
||||||
<DialogPortal>
|
(
|
||||||
<DialogOverlay className={overlayClassName} />
|
{
|
||||||
<DialogPrimitive.Content
|
className,
|
||||||
ref={ref}
|
overlayClassName,
|
||||||
className={cn(
|
showCloseButton = true,
|
||||||
'max-w-11/12 fixed left-[50%] top-[50%] z-50 grid max-h-[90vh] w-full translate-x-[-50%] translate-y-[-50%] gap-4 overflow-y-auto rounded-2xl bg-background p-6 text-text-primary shadow-lg 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-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%]',
|
children,
|
||||||
className,
|
onEscapeKeyDown: propsOnEscapeKeyDown,
|
||||||
)}
|
...props
|
||||||
{...props}
|
},
|
||||||
>
|
ref,
|
||||||
{children}
|
) => {
|
||||||
{showCloseButton && (
|
/* Handle Escape key to prevent closing dialog if a tooltip is open
|
||||||
<DialogPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-ring-primary ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground">
|
(this is a workaround in order to achieve WCAG compliance which requires
|
||||||
<X className="h-6 w-6" aria-hidden="true" />
|
that our tooltips be dismissable with Escape key) */
|
||||||
{/* eslint-disable-next-line i18next/no-literal-string */}
|
const handleEscapeKeyDown = React.useCallback(
|
||||||
<span className="sr-only">Close</span>
|
(event: KeyboardEvent) => {
|
||||||
</DialogPrimitive.Close>
|
const tooltips = document.querySelectorAll('.tooltip');
|
||||||
)}
|
|
||||||
</DialogPrimitive.Content>
|
for (const tooltip of Array.from(tooltips)) {
|
||||||
</DialogPortal>
|
const computedStyle = window.getComputedStyle(tooltip);
|
||||||
));
|
const opacity = parseFloat(computedStyle.opacity);
|
||||||
|
|
||||||
|
if (
|
||||||
|
tooltip.parentElement &&
|
||||||
|
computedStyle.display !== 'none' &&
|
||||||
|
computedStyle.visibility !== 'hidden' &&
|
||||||
|
opacity > 0
|
||||||
|
) {
|
||||||
|
event.preventDefault();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Call the original handler if it exists
|
||||||
|
propsOnEscapeKeyDown?.(event);
|
||||||
|
},
|
||||||
|
[propsOnEscapeKeyDown],
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<DialogPortal>
|
||||||
|
<DialogOverlay className={overlayClassName} />
|
||||||
|
<DialogPrimitive.Content
|
||||||
|
ref={ref}
|
||||||
|
onEscapeKeyDown={handleEscapeKeyDown}
|
||||||
|
className={cn(
|
||||||
|
'max-w-11/12 fixed left-[50%] top-[50%] z-50 grid max-h-[90vh] w-full translate-x-[-50%] translate-y-[-50%] gap-4 overflow-y-auto rounded-2xl bg-background p-6 text-text-primary shadow-lg 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-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%]',
|
||||||
|
className,
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
{showCloseButton && (
|
||||||
|
<DialogPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-ring-primary ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground">
|
||||||
|
<X className="h-6 w-6" aria-hidden="true" />
|
||||||
|
{/* eslint-disable-next-line i18next/no-literal-string */}
|
||||||
|
<span className="sr-only">Close</span>
|
||||||
|
</DialogPrimitive.Close>
|
||||||
|
)}
|
||||||
|
</DialogPrimitive.Content>
|
||||||
|
</DialogPortal>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
DialogContent.displayName = DialogPrimitive.Content.displayName;
|
DialogContent.displayName = DialogPrimitive.Content.displayName;
|
||||||
|
|
||||||
const DialogHeader = ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) => (
|
const DialogHeader = ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) => (
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue