mirror of
https://github.com/duckietm/Nitro-V3.git
synced 2026-06-19 15:06:20 +00:00
fix(furni-editor): render field tooltips in a portal (no clipping)
The Tip bubble was still clipped by the card's overflow-auto scroll container when a section was scrolled near the viewport top. Render the tooltip via createPortal to document.body with position:fixed computed from the icon rect, so it escapes every overflow/transform ancestor.
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
import { FC, useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
import { FC, useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||||
|
import { createPortal } from 'react-dom';
|
||||||
import { Button, Column, Flex, LayoutFurniIconImageView, Text } from '../../../common';
|
import { Button, Column, Flex, LayoutFurniIconImageView, Text } from '../../../common';
|
||||||
import { FurniDetail } from '../../../hooks/furni-editor';
|
import { FurniDetail } from '../../../hooks/furni-editor';
|
||||||
|
|
||||||
@@ -51,15 +52,33 @@ const Section: FC<SectionProps> = ({ title, children, defaultOpen = true }) =>
|
|||||||
const Tip: FC<{ field: string }> = ({ field }) =>
|
const Tip: FC<{ field: string }> = ({ field }) =>
|
||||||
{
|
{
|
||||||
const tip = FIELD_TIPS[field];
|
const tip = FIELD_TIPS[field];
|
||||||
|
const ref = useRef<HTMLSpanElement>(null);
|
||||||
|
const [ pos, setPos ] = useState<{ left: number; top: number } | null>(null);
|
||||||
|
|
||||||
|
const show = useCallback(() =>
|
||||||
|
{
|
||||||
|
const r = ref.current?.getBoundingClientRect();
|
||||||
|
if(r) setPos({ left: r.left + (r.width / 2), top: r.top - 6 });
|
||||||
|
}, []);
|
||||||
|
const hide = useCallback(() => setPos(null), []);
|
||||||
|
|
||||||
if(!tip) return null;
|
if(!tip) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<span className="relative group ml-0.5 inline-flex">
|
<span
|
||||||
<span className="w-3 h-3 rounded-full bg-[#1e7295] text-white text-[8px] flex items-center justify-center cursor-help font-bold">?</span>
|
ref={ ref }
|
||||||
<span className="absolute bottom-full left-1/2 -translate-x-1/2 mb-1 px-2 py-1 bg-[#333] text-white text-[10px] rounded w-44 whitespace-normal text-center leading-snug opacity-0 group-hover:opacity-100 pointer-events-none transition-opacity z-20 shadow-lg">
|
onMouseEnter={ show }
|
||||||
{ tip }
|
onMouseLeave={ hide }
|
||||||
</span>
|
className="ml-0.5 inline-flex w-3 h-3 rounded-full bg-[#1e7295] text-white text-[8px] items-center justify-center cursor-help font-bold align-middle"
|
||||||
|
>
|
||||||
|
?
|
||||||
|
{ pos && createPortal(
|
||||||
|
<span
|
||||||
|
style={ { position: 'fixed', left: pos.left, top: pos.top, transform: 'translate(-50%, -100%)', zIndex: 9999 } }
|
||||||
|
className="px-2 py-1 bg-[#333] text-white text-[10px] rounded w-44 whitespace-normal text-center leading-snug shadow-lg pointer-events-none"
|
||||||
|
>
|
||||||
|
{ tip }
|
||||||
|
</span>, document.body) }
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user