/**
 * `DialogStore` — thin Solid 2 port of Base UI React's `DialogStore`
 * (`packages/react/src/dialog/store/DialogStore.ts`).
 *
 * Mirrors `PopoverStore` from the popover compound: the actual state
 * machine lives on `<Dialog.Root>`'s local signals (open / mount /
 * transition status / interactions). This store is a thin imperative-API
 * wrapper that exposes:
 *
 * - a `PopupTriggerMap` so `<Dialog.Trigger id="...">` can register
 *   itself and `DialogHandle.open(id)` can resolve the trigger element.
 * - `setOpen(next, details)` — the writer `<Dialog.Root>` binds via
 *   `attachSetOpen` during setup. The handle's `open()` / `close()` /
 *   `openWithPayload()` all route through this.
 * - `setPayload(payload)` — same deal, for the payload slot.
 * - Synchronous `isOpen` read for imperative callers who don't want to
 *   subscribe to reactivity.
 */

import { createChangeEventDetails, REASONS } from "../../internals/change-event-details.jsx";
import { PopupTriggerMap } from "../../internals/floating-ui/popup-trigger-map.jsx";
/**
 * Internal store shape for `<Dialog.Root>`. Public surface via
 * `DialogHandle` is stable; everything else is `@internal`.
 */
export class DialogStore {
  /**
   * Trigger registry. `<Dialog.Trigger id="...">` adds itself on mount;
   * `DialogHandle.open(id)` looks up the element to seed the change
   * details' `trigger` slot.
   */

  _setOpen = null;
  _setPayload = null;
  _open = false;
  constructor() {
    this.context = {
      triggerElements: new PopupTriggerMap()
    };
  }

  /** @internal */
  attachSetOpen(fn) {
    this._setOpen = fn;
  }

  /** @internal */
  attachSetPayload(fn) {
    this._setPayload = fn;
  }

  /** @internal */
  setOpenMirror(next) {
    this._open = next;
  }

  /**
   * Imperative open-state writer. If the root is not currently mounted
   * (handle was constructed but never used inside a live `<Dialog.Root>`),
   * this is a no-op.
   */
  setOpen(next, details) {
    this._setOpen?.(next, details);
  }

  /** Imperative payload writer. No-op when no root is bound. */
  setPayload(payload) {
    this._setPayload?.(payload);
  }

  /** Synchronous snapshot — does NOT subscribe to Solid's reactive graph. */
  get isOpen() {
    return this._open;
  }
}

/**
 * `DialogHandle` — imperative + cross-tree trigger-association surface.
 *
 * Matches Base UI React's `DialogHandle` on the public method surface
 * (`open(triggerId)` / `openWithPayload(payload)` / `close()` / `isOpen`)
 * and carries an internal store that `<Dialog.Root handle={...}>` adopts.
 *
 * Usage:
 *
 * ```ts
 * const handle = Dialog.createHandle<MyPayload>();
 *
 * // ... inside the component
 * <Dialog.Root handle={handle}>
 *   <Dialog.Trigger id="t1" handle={handle}>Open</Dialog.Trigger>
 *   {/* ... *\/}
 * </Dialog.Root>
 *
 * // Later, from outside:
 * handle.open("t1");
 * handle.openWithPayload({ title: "Hello" });
 * handle.close();
 * ```
 */
export class DialogHandle {
  /** @internal */

  constructor(store) {
    this.store = store ?? new DialogStore();
  }

  /**
   * Opens the dialog. If `triggerId` is provided and a trigger with
   * that id is registered, the dialog is associated with it (focus
   * returns there on close; `aria-labelledby` / positioning downstream
   * anchors against it). A missing `triggerId` still opens the dialog
   * but skips the association.
   */
  open(triggerId) {
    const triggerElement = triggerId !== null ? this.store.context.triggerElements.getById(triggerId) : undefined;
    if (process.env.NODE_ENV !== "production") {
      if (triggerId !== null && !triggerElement) {
        console.warn(`Base UI: DialogHandle.open: No trigger found with id "${triggerId}". The dialog will open, but the trigger will not be associated with the dialog.`);
      }
    }
    this.store.setOpen(true, createChangeEventDetails(REASONS.imperativeAction, undefined, triggerElement, {
      preventUnmountOnClose: () => {}
    }));
  }

  /**
   * Opens the dialog and sets the payload. Does NOT associate the
   * dialog with any trigger — the render-function children receive
   * `{ payload }` but there's no anchor element.
   */
  openWithPayload(payload) {
    this.store.setPayload(payload);
    this.store.setOpen(true, createChangeEventDetails(REASONS.imperativeAction, undefined, undefined, {
      preventUnmountOnClose: () => {}
    }));
  }

  /**
   * Closes the dialog.
   */
  close() {
    this.store.setOpen(false, createChangeEventDetails(REASONS.imperativeAction, undefined, undefined, {
      preventUnmountOnClose: () => {}
    }));
  }

  /** Synchronous snapshot of the open state. */
  get isOpen() {
    return this.store.isOpen;
  }
}

/** Factory for `DialogHandle` — matches React's `createDialogHandle()`. */
export function createDialogHandle() {
  return new DialogHandle();
}
//# sourceMappingURL=dialog-store.jsx.map
