diff --git a/client/src/style.css b/client/src/style.css index 4839939bf8..91b4a47561 100644 --- a/client/src/style.css +++ b/client/src/style.css @@ -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); diff --git a/packages/client/src/components/Field.css b/packages/client/src/components/Field.css new file mode 100644 index 0000000000..049a0591ac --- /dev/null +++ b/packages/client/src/components/Field.css @@ -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; +} diff --git a/packages/client/src/components/Input.tsx b/packages/client/src/components/Input.tsx index f488b19144..a55a5c0486 100644 --- a/packages/client/src/components/Input.tsx +++ b/packages/client/src/components/Input.tsx @@ -1,5 +1,6 @@ import * as React from 'react'; import { cn } from '~/utils'; +import './Field.css'; export type InputProps = React.InputHTMLAttributes; diff --git a/packages/client/src/components/OriginalDialog.tsx b/packages/client/src/components/OriginalDialog.tsx index 7980f3c654..9d17779bed 100644 --- a/packages/client/src/components/OriginalDialog.tsx +++ b/packages/client/src/components/OriginalDialog.tsx @@ -178,7 +178,7 @@ const DialogContent: React.ForwardRefExoticComponent< {children} {showCloseButton && ( - )} diff --git a/packages/client/src/components/Textarea.tsx b/packages/client/src/components/Textarea.tsx index e7b408e5fc..57a2483578 100644 --- a/packages/client/src/components/Textarea.tsx +++ b/packages/client/src/components/Textarea.tsx @@ -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 {} diff --git a/packages/client/src/components/Tooltip.css b/packages/client/src/components/Tooltip.css index d885641641..7d885bc90c 100644 --- a/packages/client/src/components/Tooltip.css +++ b/packages/client/src/components/Tooltip.css @@ -1,5 +1,5 @@ .tooltip { - z-index: 900; + z-index: 150; cursor: pointer; pointer-events: auto; border-radius: 0.275rem; diff --git a/packages/client/src/components/Tooltip.tsx b/packages/client/src/components/Tooltip.tsx index 21457c9435..4d5fcc4bbd 100644 --- a/packages/client/src/components/Tooltip.tsx +++ b/packages/client/src/components/Tooltip.tsx @@ -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={ 0 ? { zIndex: popoverZIndex } : undefined} initial={{ opacity: 0, x, y }} animate={{ opacity: 1, x: 0, y: 0 }} exit={{ opacity: 0, x, y }}