/** * TooltipStore — thin Solid 2 port of Base UI React's `TooltipStore` * (`packages/react/src/tooltip/store/TooltipStore.ts`). * * Mirrors `PopoverStore` in scope: the React store carries the full * tooltip state machine; the Solid port keeps the legacy per-root * signal-based state but exposes a small imperative surface here so * `TooltipHandle` / `actionsRef` can plug in without wholesale rewriting * the root. See `src/popover/store/popover-store.ts` for the same * rationale. */ import { createChangeEventDetails, REASONS, } from "../../internals/change-event-details"; import { PopupTriggerMap } from "../../internals/floating-ui/popup-trigger-map"; import type { TooltipRootChangeEventDetails, TooltipRootChangeEventReason, } from "../tooltip-root-context"; export type TooltipStoreSetOpen = ( next: boolean, details: TooltipRootChangeEventDetails, ) => void; export class TooltipStore<_Payload = unknown> { public readonly context: { triggerElements: PopupTriggerMap }; private _setOpen: TooltipStoreSetOpen | null = null; private _open = false; constructor() { this.context = { triggerElements: new PopupTriggerMap(), }; } /** @internal */ attachSetOpen(fn: TooltipStoreSetOpen | null): void { this._setOpen = fn; } /** @internal */ setOpenMirror(next: boolean): void { this._open = next; } setOpen(next: boolean, details: TooltipRootChangeEventDetails): void { this._setOpen?.(next, details); } get isOpen(): boolean { return this._open; } } export class TooltipHandle { /** @internal */ public readonly store: TooltipStore; constructor() { this.store = new TooltipStore(); } open(triggerId: string): void { const triggerElement = this.store.context.triggerElements.getById( triggerId, ) as HTMLElement | undefined; if (!triggerElement) { throw new Error( `Base UI: TooltipHandle.open: No trigger found with id "${triggerId}".`, ); } this.store.setOpen( true, createChangeEventDetails( REASONS.imperativeAction as TooltipRootChangeEventReason, undefined, triggerElement, ) as TooltipRootChangeEventDetails, ); } close(): void { this.store.setOpen( false, createChangeEventDetails( REASONS.imperativeAction as TooltipRootChangeEventReason, undefined, undefined, ) as TooltipRootChangeEventDetails, ); } get isOpen(): boolean { return this.store.isOpen; } } export function createTooltipHandle< Payload = unknown, >(): TooltipHandle { return new TooltipHandle(); }