import { createEffect, createSignal, untrack } from "solid-js";
/**
 * Solid port of Base UI's controlled/uncontrolled state model.
 *
 * Mirrors two equivalent React Base UI mechanisms at once:
 * - `useControlled({ controlled, default })` (checkbox, select, tabs, …)
 * - the popup-store selector `state.openProp ?? state.open` plus
 *   `useControlledProp` (dialog, popover, menu, …)
 *
 * Contract:
 * - The read accessor returns the controlled prop whenever its resolved
 *   value is not `undefined`, otherwise the internal signal.
 * - The internal signal is seeded once from `default` (else `fallback`).
 * - The setter always writes the internal signal — harmless while
 *   controlled because the read prefers the prop (exactly like
 *   `DialogStore.setOpen` writing `state.open` behind `openProp`). The
 *   `onXChange` callback and any `eventDetails.isCanceled` gate stay at
 *   the component's `setX`, NOT here.
 * - Switching controlled <-> uncontrolled after creation warns, as does
 *   changing the `default*` prop while uncontrolled.
 */
export function createControlledState(options) {
  const initialControlled = untrack(options.controlled);
  const initiallyControlled = initialControlled !== undefined;
  const initialDefault = untrack(() => options.default?.());
  const stateLabel = options.state ?? "value";

  // `T` is unconstrained and may itself be a function, so seed through the
  // functional-setter form to avoid the value/updater ambiguity in
  // `createSignal`'s overloads (same idiom as navigation-menu-root).
  const [internal, setInternal] = createSignal(undefined, {
    name: `${options.name}.${stateLabel}`,
    ownedWrite: true
  });
  setInternal(() => initialDefault !== undefined ? initialDefault : options.fallback);

  // Warn on controlled <-> uncontrolled switches (Base UI dev warning;
  // quoin warns unconditionally, matching slider/floating-ui internals).
  createEffect(() => options.controlled() !== undefined, isControlled => {
    if (isControlled !== initiallyControlled) {
      console.error(`${options.name} is changing the ${initiallyControlled ? "" : "un"}controlled ${stateLabel} state to be ${initiallyControlled ? "un" : ""}controlled. Decide between controlled and uncontrolled for the lifetime of the component.`);
    }
  });
  if (options.default) {
    const readDefault = options.default;
    createEffect(() => readDefault(), next => {
      if (!initiallyControlled && !Object.is(next, initialDefault)) {
        console.error(`${options.name} is changing the default ${stateLabel} state of an uncontrolled component after initialization. The default is only read once — use the controlled ${stateLabel} prop instead.`);
      }
    });
  }
  const value = () => {
    const controlled = options.controlled();
    // The internal signal is seeded before first read, so the
    // `undefined` in its type never escapes.
    return controlled !== undefined ? controlled : internal();
  };
  const setValue = next => {
    setInternal(() => next);
  };
  return [value, setValue];
}
//# sourceMappingURL=create-controlled-state.jsx.map
