import type { JSX } from "@solidjs/web"; import { type Accessor } from "solid-js"; import { type MaybeAccessor } from "../internals/maybe-accessor.js"; /** * Why the pressed state changed. Emitted on the third arg of * `onPressedChange(next, event, reason)` and accepted by * `c.setPressed(next, event?, reason?)` / `c.toggle(event?, reason?)`. * * - `"trigger-press"` — click (or keyboard activation that bubbles to click) * on the trigger slot. * - `"imperative"` — programmatic `setPressed` / `toggle` with no * originating DOM event. * * Outer compounds that embed Toggle (ToggleGroup) translate this to their * own reason taxonomy. */ export type ToggleChangeReason = "trigger-press" | "imperative"; /** * Options for {@link createToggle}. * * Every reactive input is `MaybeAccessor` — pass an accessor to make the * value reactive, or a bare value for one-shot config. Read at use time via * `readOption(opt)`. * * **Solid-native shape (2026-04-30).** No internal state. `pressed` is * required and the consumer always owns the signal. The primitive is * a pure function from `(pressed, onPressedChange) → api`. Migration from * pre-2026-04-30: `createToggle({ defaultPressed: false })` becomes * `const [pressed, setPressed] = createSignal(false); createToggle({ pressed, onPressedChange: setPressed })`. * See `solidify.md` §6 for rationale. */ export interface CreateToggleOptions { /** * Pressed state. Consumer-owned signal — the primitive reads through * the accessor and does NOT keep an internal copy. Writes happen * via `onPressedChange` (the consumer's responsibility to update their * signal in response). */ pressed: MaybeAccessor; /** * Whether interaction is suppressed. * @default false */ disabled?: MaybeAccessor; /** * Pre-change callback. Called synchronously before any internal state * write with `(next, event, reason)`. The consumer can call * `event.preventDefault()` to veto the transition. * * Pre/post asymmetry: reading `c.pressed()` inside this handler returns * the OLD value (the setter's microtask write hasn't flushed yet). For * post-change observation use `createEffect(c.pressed, ...)`. */ onPressedChange?: (pressed: boolean, event: Event, reason: ToggleChangeReason) => void; } /** * Public API returned by {@link createToggle}. Flat accessors and setters * at the root; no `state` snapshot blob. */ export interface ToggleApi { /** Reactive accessor for the current pressed state. */ pressed: Accessor; /** Whether interaction is suppressed. */ disabled: Accessor; /** * Flip `pressed` (no-op while `disabled`). Same `event?` / `reason?` * contract as {@link setPressed}. */ toggle: (event?: Event, reason?: ToggleChangeReason) => void; /** * Imperative pressed setter. Fires `onPressedChange(next, event, reason)` * and the consumer's signal write is the only writer. */ setPressed: (next: boolean, event?: Event, reason?: ToggleChangeReason) => void; /** * Trigger slot — returns a getter-bag of HTML attributes ready for * spreading onto a `