fix: scope tooltip elevation to dialogs and restore dialog close button size

Tooltips go back to z-150 globally; inside a dialog they now borrow the
depth-aware popover z-index so they still clear nested dialogs (the Tool
Library item dialog) without outranking freshly opened modals everywhere
else. The default dialog close icon returns to its original size, and the
lc-field pointer-focus suppression ships with the package next to Input and
Textarea so external consumers get the whole mechanism from @librechat/client.
This commit is contained in:
Marco Beretta 2026-07-02 21:06:42 +02:00
parent 5c1e0b831a
commit f6eccee9c7
No known key found for this signature in database
GPG key ID: D918033D8E74CC11
7 changed files with 23 additions and 13 deletions

View file

@ -2663,7 +2663,7 @@ html {
}
.tooltip {
z-index: 900;
z-index: 150;
cursor: pointer;
border-radius: 0.275rem;
background-color: var(--surface-primary);
@ -2697,16 +2697,6 @@ html {
outline-offset: 2px;
}
/* Shared Input/Textarea (.lc-field): show the focus ring for keyboard users
only. Text inputs match :focus-visible on pointer focus too (a UA heuristic
CSS cannot distinguish), so the ring is gated on the tracked input modality. */
html[data-input-modality='pointer'] .lc-field:focus,
html[data-input-modality='pointer'] .lc-field:focus-visible {
border-color: var(--border-light);
box-shadow: none;
outline: none;
}
.popover-ui {
display: flex;
max-height: min(var(--popover-available-height, 1700px), 1700px);

View file

@ -0,0 +1,11 @@
/* Shared Input/Textarea (.lc-field): show the focus ring for keyboard users
only. Text inputs match :focus-visible on pointer focus too (a UA heuristic
CSS cannot distinguish), so the ring is gated on the input modality tracked
by useInputModality (mount it once near the app root). Without the hook the
attribute is absent and the ring always shows the safe fallback. */
html[data-input-modality='pointer'] .lc-field:focus,
html[data-input-modality='pointer'] .lc-field:focus-visible {
border-color: var(--border-light);
box-shadow: none;
outline: none;
}

View file

@ -1,5 +1,6 @@
import * as React from 'react';
import { cn } from '~/utils';
import './Field.css';
export type InputProps = React.InputHTMLAttributes<HTMLInputElement>;

View file

@ -178,7 +178,7 @@ const DialogContent: React.ForwardRefExoticComponent<
{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="size-4" aria-hidden="true" />
<X className="h-6 w-6" aria-hidden="true" />
<span className="sr-only">Close</span>
</DialogPrimitive.Close>
)}

View file

@ -2,6 +2,7 @@
import * as React from 'react';
import TextareaAutosize from 'react-textarea-autosize';
import { cn } from '~/utils';
import './Field.css';
export interface TextareaProps extends React.TextareaHTMLAttributes<HTMLTextAreaElement> {}

View file

@ -1,5 +1,5 @@
.tooltip {
z-index: 900;
z-index: 150;
cursor: pointer;
pointer-events: auto;
border-radius: 0.275rem;

View file

@ -9,6 +9,7 @@ import {
import DOMPurify from 'dompurify';
import * as Ariakit from '@ariakit/react';
import { AnimatePresence, motion } from 'framer-motion';
import { useDialogDepth, usePopoverZIndex } from './OriginalDialog';
import { cn } from '~/utils';
import './Tooltip.css';
@ -35,6 +36,11 @@ const TooltipPopup = memo(function TooltipPopup({
}) {
const mounted = Ariakit.useStoreState(store, (state) => state.mounted);
const placement = Ariakit.useStoreState(store, (state) => state.placement);
/** Tooltips portal to body at z-150, which nested dialogs (z 200+) cover
* inside a dialog, borrow the popover's depth-aware z-index; outside, keep
* the stylesheet default so tooltips never outrank freshly opened dialogs. */
const dialogDepth = useDialogDepth();
const popoverZIndex = usePopoverZIndex();
const sanitizer = useMemo(() => {
const instance = DOMPurify();
@ -89,6 +95,7 @@ const TooltipPopup = memo(function TooltipPopup({
className="tooltip"
render={
<motion.div
style={dialogDepth > 0 ? { zIndex: popoverZIndex } : undefined}
initial={{ opacity: 0, x, y }}
animate={{ opacity: 1, x: 0, y: 0 }}
exit={{ opacity: 0, x, y }}