import { useEffect, useMemo, useRef } from 'react' import { hideHint, showHint } from './HintHost' import type { HintPositionOffset, ShowHintOptions } from './HintHost' export type SceneHintProps = { /** 是否展示提示 */ when: boolean /** 提示文本(建议直接传 string children) */ children: string /** 延迟展示(ms) */ delayMs?: number /** 自动消失时间(ms)。不传则使用默认值(2000) */ durationMs?: number /** 是否常驻 */ persistent?: boolean /** 相对中心点微调位置 */ offset?: HintPositionOffset /** 自定义层级 */ zIndex?: number /** 进入 when=true 时只展示一次(后续 when=true 的 rerender 不会重复触发) */ once?: boolean /** * 触发 key:当此值变化时(且 when=true)会重新触发一次 showHint。 * 用于“同一个提示需要再次弹出”的场景。 */ triggerKey?: string | number /** when 变为 false / 卸载时是否自动 hide */ hideOnCleanup?: boolean } export function SceneHint({ when, children, delayMs = 0, durationMs, persistent = false, offset, zIndex, once = false, triggerKey, hideOnCleanup = true, }: SceneHintProps) { const shownOnceRef = useRef(false) const delayTimerRef = useRef(null) const text = useMemo(() => { return typeof children === 'string' ? children : String(children ?? '') }, [children]) useEffect(() => { if (!when) { shownOnceRef.current = false if (hideOnCleanup) hideHint() return } if (once && shownOnceRef.current) return const options: ShowHintOptions = { persistent, ...(durationMs !== undefined ? { durationMs } : null), ...(offset ? { offset } : null), ...(zIndex !== undefined ? { zIndex } : null), } if (delayMs > 0) { delayTimerRef.current = window.setTimeout(() => { showHint(text, options) shownOnceRef.current = true }, delayMs) } else { showHint(text, options) shownOnceRef.current = true } return () => { if (delayTimerRef.current) { window.clearTimeout(delayTimerRef.current) delayTimerRef.current = null } if (hideOnCleanup) hideHint() } // eslint-disable-next-line react-hooks/exhaustive-deps }, [ when, text, delayMs, durationMs, persistent, offset?.x, offset?.y, zIndex, once, triggerKey, hideOnCleanup, ]) return null }