import { createContext, createMemo, runWithOwner, untrack, useContext } from "solid-js";
import { readOption } from "./maybe-accessor.jsx";
import { SNAPSHOT_KEYS, snapshotKeys } from "./observability/snapshot.jsx";

/**
 * Why a popup's open state changed.
 *
 * Compounds may extend this with their own reason literals — e.g.
 * `"trigger-hover"` for Tooltip. The common reasons are surfaced here so
 * `createPopupCore` can emit a meaningful default without knowing the
 * per-compound vocabulary.
 *
 * - `"trigger-press"` — user activated the trigger (click / Enter / Space).
 * - `"imperative"` — `popup.setOpen()` called with no originating DOM event.
 * - `"escape-key"` — Escape key dismissed the popup.
 * - `"outside-press"` — pointer press outside the popup dismissed it.
 */

/**
 * Options accepted by {@link createPopupCore}. Every reactive field is
 * `MaybeAccessor<T>` — pass an accessor to keep the option live.
 */

/**
 * Public API returned by {@link createPopupCore}.
 */

const PopupCoreContext = createContext(null);

/**
 * Read the nearest {@link PopupCoreApi} from a `<popup.Provider>`.
 * Throws unless `optional` is true.
 */

export function usePopupCore(optional) {
  const ctx = useContext(PopupCoreContext);
  if (ctx == null && !optional) {
    throw new Error("Base UI: usePopupCore() must be called inside a <popup.Provider>.");
  }
  return ctx;
}

/**
 * Shared headless primitive for popup compounds (Tooltip, Popover, Dialog,
 * PreviewCard, AlertDialog, Drawer). Owns:
 *
 *  - `open` memo — reads through the consumer's accessor.
 *  - `disabled` memo — guards setOpen / toggle.
 *  - `setOpen` / `toggle` — pure event-emitters that fire `onOpenChange`
 *    via `runWithOwner(null, ...)`.
 *  - `Provider` — optional context provider.
 *
 * DOM machinery (floating-ui, portal, focus trap, scroll lock, animation)
 * lives in the per-compound `<X.Root>` wrappers that compose this.
 */
export function createPopupCore(options) {
  const open = createMemo(() => Boolean(readOption(options.open)), {
    name: "popup.open"
  });
  const disabled = createMemo(() => Boolean(readOption(options.disabled)), {
    name: "popup.disabled"
  });
  const setOpen = (next, event, reason = "imperative") => {
    const ev = event ?? new Event("openchange", {
      cancelable: true
    });
    // Escape the reactive owner so consumer signal writes inside
    // onOpenChange don't trip SIGNAL_WRITE_IN_OWNED_SCOPE.
    runWithOwner(null, () => options.onOpenChange?.(next, ev, reason));
  };
  const toggle = (event, reason) => {
    if (untrack(disabled)) return;
    setOpen(!untrack(open), event, reason);
  };
  const api = {
    open,
    disabled,
    setOpen,
    toggle,
    Provider: props => <PopupCoreContext value={api}>
				{props.children}
			</PopupCoreContext>
  };
  api[SNAPSHOT_KEYS] = POPUP_CORE_SNAPSHOT_KEYS;
  return api;
}
const POPUP_CORE_SNAPSHOT_KEYS = snapshotKeys("open", "disabled");
//# sourceMappingURL=create-popup-core.jsx.map
