import { dynamic } from "@solidjs/web";
import { createSignal, omit } from "solid-js";
import { createControlledState } from "../../internals/create-controlled-state.jsx";
import { readOption } from "../../internals/maybe-accessor.jsx";
import { mergeRootProps } from "../../internals/merge-root-props.jsx";
import { createMountTransition } from "../../internals/use-mount-transition/use-mount-transition.jsx";
import { createCollapsible } from "../create-collapsible.jsx";

/**
 * Change-reason namespace for `Collapsible.Root` (shipped public type).
 * Mirrors Base UI React: explicit trigger presses use {@link REASONS.triggerPress};
 * indirect flows (e.g. `beforematch` from `hiddenUntilFound`) use {@link REASONS.none}.
 *
 * NOTE: the new primitive's `onOpenChange(next, event, reason)` signature uses
 * the `CollapsibleChangeReason` taxonomy directly. This `BaseUIChangeEventDetails`-
 * shaped type is kept as a public re-export for downstream consumers that
 * imported it from `quoin` before the primitive rewrite.
 */

/**
 * Public state surface — kept as a shipped type for any consumer projecting
 * accordion/collapsible state through their own `data-*` mappings. Stage-01c
 * cleanup: the wrapper itself no longer reads `transitionStatus` (it's now
 * owned by the panel's local `createMountTransition`); this type still
 * surfaces it for `accordionItemStateAttributesMapping` and any consumer-side
 * mappings that rely on the same shape.
 */

/**
 * Props for {@link CollapsibleRoot}.
 *
 * Stage-01 spike rewire: the wrapper is a structural adapter over the
 * `createCollapsible` primitive (axes A + P).
 *
 * - `onOpenChange` is `(open, event, reason)` — cancel via
 *   `event.preventDefault()` (axis C). Reason is the third argument:
 *   `"trigger-press"` / `"beforematch"` / `"imperative"`.
 * - `render={(p) => ...}` is replaced by `as="..."` (axis G).
 * - Optional `api` prop lets a consumer pre-build the primitive (so they can
 *   `createEffect(c.open, ...)` outside the wrapper) and pass it back in.
 */

/**
 * Groups all parts of the collapsible. Renders a `<div>` (or `as` override).
 *
 * Implementation notes:
 *
 * - Calls `createCollapsible` (or reuses `props.api`) once at setup.
 * - Provides the `CollapsibleContext` (consumed by `<Collapsible.Trigger>`,
 *   `<Collapsible.Panel>`, the directives, and any inline `useCollapsible()`).
 * - Owns its own `createMountTransition(c.open)` instance bound to the root
 *   element. Emits `data-open` / `data-closed` plus `data-starting-style` /
 *   `data-ending-style` so consumers can drive root-level CSS transitions
 *   independently from the panel's own lifecycle. The Panel wrapper has its
 *   own instance for panel-anchored animation — the two are independent
 *   (each tracks the CSS animations on its own element).
 */
export function CollapsibleRoot(props) {
  // Controlled / uncontrolled open state (Base UI `open` / `defaultOpen`
  // contract): the `open` prop wins while its resolved value is defined;
  // otherwise an internal signal (seeded once from `defaultOpen`) backs
  // the state. Unused when a pre-built `api` is supplied.
  const [resolvedOpen, setUncontrolledOpen] = createControlledState({
    controlled: () => {
      const controlled = readOption(props.open);
      return controlled === undefined ? undefined : Boolean(controlled);
    },
    default: () => readOption(props.defaultOpen),
    fallback: false,
    name: "<Collapsible.Root>",
    state: "open"
  });
  const c = props.api ?? createCollapsible({
    open: resolvedOpen,
    disabled: () => Boolean(readOption(props.disabled)),
    onOpenChange: (next, event, reason) => {
      // Mirror React's `useCollapsibleRoot.handleTrigger`: fire the
      // consumer callback first, honor the veto (quoin's cancel
      // channel is `event.preventDefault()`), then write the
      // uncontrolled state (ignored for reads while the `open`
      // prop is controlled — the consumer's signal write is the
      // source of truth).
      props.onOpenChange?.(next, event, reason);
      if (event.defaultPrevented) return;
      setUncontrolledOpen(next);
    },
    keepMounted: () => Boolean(readOption(props.keepMounted)),
    hiddenUntilFound: () => Boolean(readOption(props.hiddenUntilFound))
  });

  // Root-level animation lifecycle. Bound to the root element so
  // `data-starting-style` / `data-ending-style` track the root's own CSS
  // transitions (independent from the panel's instance).
  const [rootEl, setRootEl] = createSignal(null);
  const m = createMountTransition(c.open, {
    panelElement: rootEl,
    keepMounted: true
  });

  // Root-level reactive data attrs.
  const rootInternal = {
    ref: setRootEl,
    get "data-open"() {
      return c.open() ? "" : undefined;
    },
    get "data-closed"() {
      return c.open() ? undefined : "";
    },
    get "data-starting-style"() {
      return m.transitionStatus() === "starting" ? "" : undefined;
    },
    get "data-ending-style"() {
      return m.transitionStatus() === "ending" ? "" : undefined;
    }
  };

  // Strip our own keys before spreading user HTML attributes through.
  const userHtmlProps = omit(props, "api", "as", "children", "defaultOpen", "disabled", "hiddenUntilFound", "keepMounted", "onOpenChange", "open");

  // Bind the merged slot bag to a `const` BEFORE the JSX spread. This is
  // hydration-critical, not cosmetic: when the Solid SSR compiler sees a spread
  // of an inline *call expression* (`<Tag {...mergeRootProps(...)}>`) it
  // wraps it in a lazy thunk `() => mergeRootProps(...)`. The server's
  // `dynamic()` runtime resolves that thunk on a DIFFERENT child-id allocation
  // path than the client does, which (a) drops every merged attribute from the
  // SSR markup and (b) shifts the hydration keys by one slot — throwing
  // "Hydration Mismatch". Spreading a pre-bound *variable* (`{...merged}`) makes
  // the compiler pass the object straight through, exactly as `<Tabs.Root>`
  // does (which is why Tabs already hydrated cleanly). See
  // `merge-root-props.ts` for the getter-bag shape.
  const merged = mergeRootProps(rootInternal, userHtmlProps);
  const Tag = dynamic(() => props.as ?? "div");
  return <c.Provider>
			<Tag {...merged}>{props.children}</Tag>
		</c.Provider>;
}
//# sourceMappingURL=collapsible-root.jsx.map
