import { Tooltip as KobalteTooltip } from "@kobalte/core/tooltip" import { createEffect, Match, onCleanup, splitProps, Switch, type JSX } from "solid-js" import type { ComponentProps } from "solid-js" import { createStore } from "solid-js/store" export interface TooltipProps extends ComponentProps { value: JSX.Element class?: string contentClass?: string contentStyle?: JSX.CSSProperties inactive?: boolean forceOpen?: boolean } export interface TooltipKeybindProps extends Omit { title: string keybind: string } export function TooltipKeybind(props: TooltipKeybindProps) { const [local, others] = splitProps(props, ["title", "keybind"]) return ( {local.title} {local.keybind} } /> ) } export function Tooltip(props: TooltipProps) { let ref: HTMLDivElement | undefined const [state, setState] = createStore({ open: false, block: false, expand: false, }) const [local, others] = splitProps(props, [ "children", "class", "contentClass", "contentStyle", "inactive", "forceOpen", "ignoreSafeArea", "value", ]) const close = () => setState("open", false) const inside = () => { const active = document.activeElement if (!ref || !active) return false return ref.contains(active) } const drop = (expand = state.expand) => { if (expand) return if (ref?.matches(":hover")) return if (inside()) return setState("block", false) } const sync = () => { const expand = !!ref?.querySelector('[aria-expanded="true"], [data-expanded]') setState("expand", expand) if (expand) { setState("block", true) close() return } drop(expand) } const arm = () => { setState("block", true) close() } const leave = () => { if (!inside()) close() drop() } createEffect(() => { if (!ref) return sync() const obs = new MutationObserver(sync) obs.observe(ref, { subtree: true, childList: true, attributes: true, attributeFilter: ["aria-expanded", "data-expanded"], }) onCleanup(() => obs.disconnect()) }) return ( {local.children} { if (local.forceOpen) return if (state.block && open) return setState("open", open) }} > { if (event.key !== "Enter" && event.key !== " ") return arm() }} onPointerLeave={leave} onFocusOut={() => requestAnimationFrame(() => drop())} > {local.children} {local.value} {/* */} ) }