/** A next-value or an updater function, mirroring `useState`'s setter argument. */ export type ControllableStateAction = T | ((previous: T) => T); export interface UseControllableStateOptions { /** * The controlled value. When this is anything other than `undefined` the * component is controlled: internal state is never written, and `setValue` * only reports the requested value through `onChange`. */ value?: T; /** * Initial value used while uncontrolled. Accepts a factory, like `useState`, * for defaults that are expensive or must not be recomputed every render * (`() => new Date()`, a value read back from storage, …). * * Same caveat as `useState`: a `T` that is itself a function must be wrapped * in a factory, since a function argument is always treated as one. */ defaultValue?: T | (() => T); /** * Value used while uncontrolled when `defaultValue` is also `undefined` — * the component's own "empty" value (`''`, `0`, `false`, `[]`, …). */ finalValue?: T; /** * Called with every requested value, in both modes, synchronously from the * caller's event handler. Extra arguments passed to `setValue` are forwarded * after the value, so component-specific payloads survive. */ onChange?: (value: T, ...payload: any[]) => void; } export type UseControllableStateReturn = readonly [ /** The value to render — the controlled prop, or internal state. */ T, /** Request a new value. Accepts a value or an updater function. */ (next: ControllableStateAction, ...payload: any[]) => void, /** `true` while the `value` prop is driving the component. */ boolean ]; /** * Single source of truth for the controlled / uncontrolled split that every * value-bearing component needs. Replaces the hand-rolled * `isControlled` + `internalValue` + sync-effect trio. * * Semantics (deliberately synchronous, matching the rest of this library): * - Controlled (`value !== undefined`): `setValue` writes nothing locally and * calls `onChange`. The parent owns the value; if it ignores `onChange`, * nothing moves — which is the point of controlled mode. * - Uncontrolled: `setValue` writes internal state **and** calls `onChange` in * the same tick, so handlers fire before paint rather than in an effect. * - Switching controlled → uncontrolled seeds internal state with the last * controlled value, so the UI holds its position instead of snapping back to * `defaultValue`. Switching modes at all logs a warning in `__DEV__`. * * `setValue` is referentially stable for the lifetime of the component, so it * is safe in dependency arrays and in memoized context values. * * @example Uncontrolled with a default * const [value, setValue] = useControllableState({ * value: props.value, * defaultValue: props.defaultValue, * finalValue: '', * onChange: props.onChange, * }); * * @example Updater form * setValue((previous) => previous + 1); * * @example Extra payload forwarded to onChange * setValue(nextDate, { source: 'calendar' }); */ export declare function useControllableState({ value, defaultValue, finalValue, onChange, }: UseControllableStateOptions): UseControllableStateReturn;