import { type TemplateResult } from "lit-html";
import type { DirectiveResult } from "lit-html/directive.js";
import type { PopupPlacement } from "./popupPlacement";
/**
* A readable boolean atom — any callable that returns a boolean and also
* exposes a `get()` method (compatible with mates `atom(false)`).
* Used by the `open` option of `popup()` to drive controlled mode.
*/
export interface PopupOpenAtom {
(): boolean;
get(): boolean;
}
/** Accepted value for `PopupOptions.open` — an atom or a plain boolean. */
export type PopupOpenValue = PopupOpenAtom | boolean;
export type { PopupPlacement } from "./popupPlacement";
export interface PopupOptions {
/** default "bottom-start" */
position?: PopupPlacement;
/** px gap between anchor and floating panel, default 4 */
gap?: number;
style?: Record;
/** Set the floating panel's width to exactly match the anchor element's width. */
matchAnchorWidth?: boolean;
/**
* When true, the floating element is removed from `document.body` on close
* and re-appended on open. This keeps the DOM clean when the panel content
* is expensive (e.g. a calendar with 42 day cells).
* Default: false (legacy behaviour — panel stays in DOM, display:none).
*/
destroyOnClose?: boolean;
/**
* Called after the panel is shown and positioned (each time it opens).
* Use to move focus into the panel for keyboard navigation.
*/
onOpen?: (panel: HTMLElement) => void;
/**
* Called when the panel closes (outside click, Escape, or toggle).
* Receives the anchor element and the floating panel element.
* With `destroyOnClose: true`, the floating element is passed so the
* consumer can remove it after any exit animation completes.
* If the consumer calls `floating.remove()` itself, `popup()` will NOT
* call it again — it checks `floating.isConnected` before removing.
*/
onClose?: (anchor: HTMLElement, floating: HTMLElement) => void;
/**
* **Controlled mode** — pass a boolean atom to take full control of
* open/close state. When provided:
* - No `click` listener is attached to the anchor element.
* - The panel opens when `open()` becomes `true` and closes when it
* becomes `false` (evaluated on every render update).
* - Outside-click and Escape are **not** wired automatically; the caller
* is responsible for setting the atom to `false` when appropriate.
*
* @example
* const isOpen = atom(false);
* html`
`
*/
open?: PopupOpenValue;
/**
* Override the z-index of the floating panel.
* Use `600` (or `--md-z-popup-above-modal`) when the popup must appear
* above an open dialog. Defaults to the floating-container default (9999).
*/
zIndex?: number | string;
/**
* When true, suppresses any CSS animations on the floating panel element.
* Useful for tour cards and other cases where you want instant appearance.
*/
disableAnimation?: boolean;
}
/**
* `popup(content, options?)` — attach an anchored floating panel to any element.
*
* **Toggle mode** (default) — clicking the anchor opens/closes the panel.
* Outside-click and Escape close it automatically.
*
* **Controlled mode** — pass `options.open` with a boolean atom to take full
* control. No click listener is attached; the panel opens/closes whenever
* the atom value changes. Outside-click and Escape are NOT wired automatically —
* the caller is responsible for setting the atom to `false`.
*
* Pure `position:fixed` — no Popover API, no portal wrapper needed.
* Repositions on scroll and resize.
*
* @example — toggle (default)
* html``
*
* @example — controlled (combo-box / autocomplete)
* const isOpen = atom(false);
* html`
*