PettyUI/packages/core/src/components/hover-card/hover-card-context.ts
Mats Bosson 8f075f1792 feat: add 12 components — Tooltip, Popover, HoverCard, Alert, Badge,
Skeleton, Breadcrumbs, Link, Button, Image, Meter, NumberField
Floating components: Tooltip (hover/focus), Popover (click, with focus
trap and dismiss), HoverCard (hover with safe area).
Simple components: Alert (role=alert), Badge (role=status), Skeleton
(loading placeholder with data attributes).
Navigation: Breadcrumbs (nav>ol>li with separators), Link (accessible
anchor with disabled), Button (with disabled click suppression).
Data/Form: Image (Img+Fallback with loading status), Meter (like
Progress for known ranges), NumberField (spinbutton with inc/dec).
302 tests across 46 files, typecheck clean, build produces 176 files.
2026-03-29 19:34:13 +07:00

69 lines
2.2 KiB
TypeScript

import type { Accessor, JSX } from "solid-js";
import { createContext, useContext } from "solid-js";
/** Internal context shared between all HoverCard sub-components. */
export interface InternalHoverCardContextValue {
isOpen: Accessor<boolean>;
open: () => void;
close: () => void;
triggerRef: Accessor<HTMLElement | null>;
setTriggerRef: (el: HTMLElement | null) => void;
contentRef: Accessor<HTMLElement | null>;
setContentRef: (el: HTMLElement | null) => void;
contentId: string;
triggerId: string;
floatingStyle: Accessor<JSX.CSSProperties>;
/** Open delay in ms. */
openDelay: number;
/** Close delay in ms. */
closeDelay: number;
/** Schedule open after openDelay. */
scheduleOpen: () => void;
/** Schedule close after closeDelay. */
scheduleClose: () => void;
/** Cancel any pending open/close timer. */
cancelTimers: () => void;
}
const InternalHoverCardContext = createContext<InternalHoverCardContextValue>();
/**
* Returns the internal HoverCard context. Throws if used outside HoverCard.
*/
export function useInternalHoverCardContext(): InternalHoverCardContextValue {
const ctx = useContext(InternalHoverCardContext);
if (!ctx) {
throw new Error(
"[PettyUI] HoverCard parts must be used inside <HoverCard>.\n" +
" Fix: <HoverCard>\n" +
" <HoverCard.Trigger>...</HoverCard.Trigger>\n" +
" <HoverCard.Content>...</HoverCard.Content>\n" +
" </HoverCard>",
);
}
return ctx;
}
export const InternalHoverCardContextProvider = InternalHoverCardContext.Provider;
/** Public context exposed via HoverCard.useContext(). */
export interface HoverCardContextValue {
/** Whether the hover card is open. */
open: Accessor<boolean>;
}
const HoverCardPublicContext = createContext<HoverCardContextValue>();
/**
* Returns the public HoverCard context. Throws if used outside HoverCard.
*/
export function useHoverCardContext(): HoverCardContextValue {
const ctx = useContext(HoverCardPublicContext);
if (!ctx) {
throw new Error("[PettyUI] HoverCard.useContext() called outside of <HoverCard>.");
}
return ctx;
}
export const HoverCardPublicContextProvider = HoverCardPublicContext.Provider;