import type { JSX } from "@solidjs/web";
import {
type Accessor,
createContext,
createMemo,
untrack,
useContext,
} from "solid-js";
import { makeSlotRefDirective } from "../internals/make-slot-ref-directive";
import { type MaybeAccessor, readOption } from "../internals/maybe-accessor";
import { mergeRootProps } from "../internals/merge-root-props";
import {
SNAPSHOT_KEYS,
type Snapshottable,
snapshotKeys,
} from "../internals/observability/snapshot";
/**
* Why the checked state changed. Emitted on the third arg of
* `onCheckedChange(next, event, reason)`.
*
* - `"trigger-press"` — click / keyboard activation that bubbles to click on
* the switch root, OR a change on the co-located hidden `` (AT /
* keyboard activating the checkbox directly).
* - `"imperative"` — programmatic `setChecked` / `toggle` with no originating
* DOM event.
*/
export type SwitchChangeReason = "trigger-press" | "imperative";
/**
* Options for {@link createSwitch}. Every reactive input is
* `MaybeAccessor` — pass an accessor to make the value reactive.
*
* **Solid-native shape (2026-04-30).** No internal state. `checked` is
* required and the consumer always owns the signal. The primitive is a pure
* function from `(checked, onCheckedChange) → api`. Migration:
* `createSwitch({ defaultChecked: false })` becomes
* `const [checked, setChecked] = createSignal(false); createSwitch({ checked, onCheckedChange: setChecked })`.
* See `solidify.md` §6 for rationale.
*/
export interface CreateSwitchOptions {
/**
* Checked state. Consumer-owned signal — the primitive reads through
* the accessor and does NOT keep an internal copy. Writes happen
* via `onCheckedChange` (the consumer's responsibility to update their
* signal in response).
*/
checked: MaybeAccessor;
/**
* Whether interaction is suppressed.
* @default false
*/
disabled?: MaybeAccessor;
/**
* Whether the switch is read-only — focusable but not activatable.
* @default false
*/
readOnly?: MaybeAccessor;
/**
* Whether the switch must be on for form submission.
* @default false
*/
required?: MaybeAccessor;
/**
* Pre-change callback. `event.preventDefault()` is now a no-op for
* the primitive (the consumer's signal write is the only writer);
* left in the signature for parity with other event channels.
*
* Pre/post asymmetry: reading `c.checked()` inside this handler returns
* the OLD value (the consumer's signal write hasn't flushed yet). For
* post-change observation use `createEffect(c.checked, ...)`.
*/
onCheckedChange?: (
checked: boolean,
event: Event,
reason: SwitchChangeReason,
) => void;
}
/**
* Public API returned by {@link createSwitch}. Flat accessors and setters at
* the root; no `state` snapshot blob.
*/
export interface SwitchApi {
checked: Accessor;
disabled: Accessor;
readOnly: Accessor;
required: Accessor;
/**
* Flip `checked`. No-op while `disabled` or `readOnly`. Same `event?` /
* `reason?` contract as {@link setChecked}.
*/
toggle: (event?: Event, reason?: SwitchChangeReason) => void;
/**
* Pure event-emitter: fires `onCheckedChange(next, event, reason)`.
* No-op while `disabled` or `readOnly`. The consumer's signal write
* (in their `onCheckedChange` handler) is the only writer.
*/
setChecked: (
next: boolean,
event?: Event,
reason?: SwitchChangeReason,
) => void;
/**
* Trigger slot — getter-bag of attributes ready for spreading onto a
* `