/
Alex_Ural
/
opencode
Обзор
Документация
Войти
/
Alex_Ural
/
opencode
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
dev
packages/ui/src/components/tooltip.tsx
163 строки
4 KB
usrnk1
feat(desktop): polish tooltips and session search (#34632)
30 июн 2026, 18:00
Не верифицирован
30 июн 2026, 18:00
fced9c5
Код
Авторство
О чём код?
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<typeof KobalteTooltip> { value: JSX.Element class?: string contentClass?: string contentStyle?: JSX.CSSProperties inactive?: boolean forceOpen?: boolean } export interface TooltipKeybindProps extends Omit<TooltipProps, "value"> { title: string keybind: string } export function TooltipKeybind(props: TooltipKeybindProps) { const [local, others] = splitProps(props, ["title", "keybind"]) return ( <Tooltip {...others} value={ <div data-slot="tooltip-keybind"> <span>{local.title}</span> <span data-slot="tooltip-keybind-key">{local.keybind}</span> </div> } /> ) } 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()) }) let justClickedTrigger = false return ( <Switch> <Match when={local.inactive}>{local.children}</Match> <Match when={true}> <KobalteTooltip gutter={4} openDelay={400} skipDelayDuration={300} {...others} closeDelay={0} ignoreSafeArea={local.ignoreSafeArea ?? true} open={local.forceOpen || state.open} onOpenChange={(open) => { if (local.forceOpen) return if (state.block && open) return if (justClickedTrigger) { justClickedTrigger = false return } setState("open", open) }} > <KobalteTooltip.Trigger ref={ref} as={"div"} data-component="tooltip-trigger" class={local.class} onPointerDownCapture={arm} onKeyDownCapture={(event: KeyboardEvent) => { if (event.key !== "Enter" && event.key !== " ") return arm() }} onPointerLeave={leave} onFocusOut={() => requestAnimationFrame(() => drop())} > {local.children} </KobalteTooltip.Trigger> <KobalteTooltip.Portal> <KobalteTooltip.Content data-component="tooltip" data-placement={props.placement} data-force-open={local.forceOpen} class={local.contentClass} style={local.contentStyle} onPointerDownOutside={(e) => { if (ref === e.target || (e.target instanceof Node && ref?.contains(e.target))) { justClickedTrigger = true } e.preventDefault() }} > {local.value} {/* <KobalteTooltip.Arrow data-slot="tooltip-arrow" /> */} </KobalteTooltip.Content> </KobalteTooltip.Portal> </KobalteTooltip> </Match> </Switch> ) }