import type { ReactiveController, ReactiveControllerHost } from "lit"; export type PopoverSide = "top" | "bottom" | "left" | "right"; export type PopoverPlacement = PopoverSide | "auto"; export type PopoverAlign = "start" | "center" | "end"; export type MaxWidthMode = "cap" | "fill"; export type CloseReason = "api" | "toggle" | "escape" | "light-dismiss" | "group"; type ArrowAlign = "center" | "start" | "end"; type ScrollContainerMode = "auto" | "window"; /** Named animation presets; consumer selects by name. */ export type PopoverPreset = "none" | "fade" | "scale" | "slide" | "iosMenu" | "iosSheet" | "materialMenu" | "materialSheet" | "floaty" | "soft" | "sharp" | "blurIn" | "blurFade" | "zoomFromAnchor" | "zoomFromCorner" | "flip3d" | "card3d" | "tilt3d" | "depth3d" | "rotate3d" | "springy" | "bouncy" | "glide" | "pop" | "drop" | "grow"; export type PopoverPresetConfig = { enterPx?: number; exitPx?: number; enterScale?: number; exitScale?: number; blurInPx?: number; blurOutPx?: number; perspectivePx?: number; rotateDeg?: number; tiltDeg?: number; origin?: "auto" | "anchor" | "center" | "corner"; easingOpen?: string; easingClose?: string; enterDuration?: number; exitDuration?: number; }; export interface PopoverControllerOptions { getAnchor: () => HTMLElement | null; getPopover: () => HTMLElement | null; cssVarLeft?: string; cssVarTop?: string; cssVarWidth?: string; getPlacement?: () => PopoverPlacement; getAlign?: () => PopoverAlign; getGap?: () => number; getPadding?: () => number; getMatchAnchorWidth?: () => boolean; getMaxWidthToViewport?: () => boolean; getMaxWidthMode?: () => MaxWidthMode; getFlip?: () => boolean; getFlipOrder?: () => PopoverSide[]; getPreset?: () => PopoverPreset; getDuration?: () => number; getCloseDuration?: () => number; getAnimateReposition?: () => boolean; getRepositionMs?: () => number; getCloseOnEscape?: () => boolean; getRestoreFocusOnClose?: () => boolean; getCloseOnOutside?: () => boolean; getIgnoreOutsideSelector?: () => string; getIgnoreOutsideAttr?: () => string; placement?: PopoverPlacement; align?: PopoverAlign; gap?: number; padding?: number; matchAnchorWidth?: boolean; maxWidthToViewport?: boolean; maxWidthMode?: MaxWidthMode; flip?: boolean; flipOrder?: PopoverSide[]; preset?: PopoverPreset; duration?: number; closeDuration?: number; animateReposition?: boolean; repositionMs?: number; closeOnEscape?: boolean; restoreFocusOnClose?: boolean; closeOnOutside?: boolean; ignoreOutsideSelector?: string; ignoreOutsideAttr?: string; focusOnOpen?: () => void; scrollContainer?: ScrollContainerMode | HTMLElement; groupEventName?: string; groupId?: unknown; onOpenChange?: (open: boolean, meta: { reason: CloseReason; }) => void; /** Focus target on close; defaults to {@link getAnchor} when omitted. */ getFocusTarget?: () => HTMLElement | null; sideAttr?: string; respectReducedMotion?: boolean; } /** * PopoverController with Reactive Getter Bindings * - Automatically reads latest values from host component via getter functions * - No manual updates needed when host properties change * - WAAPI preset animations with side-aware enter/exit * - Smooth reposition animation on flip/move */ export declare class PopoverController implements ReactiveController { private host; private _open; private raf; private anchorRO?; private popoverRO?; private boundScrollParents; private visualViewport?; /** When true, global listeners and observers are attached (deferred until first open for perf with many instances). */ private _listenersAttached; private lastCloseReason; private lastFocusedEl; private hasEverOpened; private _skipNextReposition; private lastMeta; private _phase; private presetAnim?; private moveAnim?; private static createGetter; private opts; constructor(host: ReactiveControllerHost, options: PopoverControllerOptions); get open(): boolean; get meta(): { place: PopoverSide; arrowAlign: ArrowAlign; }; hostConnected(): void; hostDisconnected(): void; /** Attach window/document listeners and observers. Called on first open. */ private attachGlobalListeners; /** Remove window/document listeners and observers. Called on close and on hostDisconnected. */ private detachGlobalListenersIfAttached; refreshTargets(): void; /** Wire to popover element: @toggle=${controller.onToggle} */ onToggle: (e: Event) => void; toggle(): void; openPopover(): void; private onDocumentPointerDown; closePopover(reason?: CloseReason): Promise; private normalizeFlipOrder; private defaultOrderFromPlacement; position(): void; private vec; private prefersReducedMotion; /** sets transformOrigin according to preset + side */ private computeOrigin; private kf; private presetRegistry; private getPresetKeyframes; private getBaseDefaults; private playPreset; private checkForConflictingCSS; private animateMove; private is3dPreset; private setSideAttr; private setupObserversAndScrollParents; private bindScroll; private teardownScrollParents; private getScrollParents; private onViewportMove; private onKeydown; private onGroupOpen; private captureFocusBeforeOpen; private elementIsTriggerRelated; private restoreFocus; private ensurePopoverMarginZero; /** * Utility method to manually update a specific option * (Useful for edge cases where you need direct control) */ updateOption(key: T, value: typeof this.opts[T]): void; } export {};