@zeix/cause-effect
Version:
Cause & Effect - reactive state management primitives library for TypeScript.
88 lines (87 loc) • 3.65 kB
TypeScript
import { type Cleanup, type SignalOptions } from '../graph';
/**
* A read-only signal that tracks external input and updates a state value as long as it is active.
*
* @template T - The type of value produced by the sensor
*/
type Sensor<T extends {}> = {
readonly [Symbol.toStringTag]: 'Sensor';
/**
* Gets the current value of the sensor.
* When called inside another reactive context, creates a dependency.
* @returns The sensor value
* @throws UnsetSignalValueError If the sensor value is still unset when read.
*/
get(): T;
};
/**
* Configuration options for `createSensor`.
*
* @template T - The type of value produced by the sensor
*/
type SensorOptions<T extends {}> = SignalOptions<T> & {
/**
* Optional initial value. Avoids `UnsetSignalValueError` on first read
* before the watched callback fires.
*/
value?: T;
};
/**
* Setup callback for `createSensor`. Invoked when the sensor gains its first downstream
* subscriber; receives a `set` function to push new values into the graph.
*
* @template T - The type of value produced by the sensor
* @param set - Updates the sensor value and propagates the change to subscribers
* @returns A cleanup function invoked when the sensor loses all subscribers
*/
type SensorCallback<T extends {}> = (set: (next: T) => void) => Cleanup;
/**
* Creates a sensor that tracks external input and updates a state value as long as it is active.
* Sensors get activated when they are first accessed by an effect and deactivated when they are
* no longer watched. This lazy activation pattern ensures resources are only consumed when needed.
*
* @since 0.18.0
* @template T - The type of value produced by the sensor
* @param watched - The callback invoked when the sensor starts being watched, receives a `set` function and returns a cleanup function.
* @param options - Optional configuration for the sensor.
* @param options.value - Optional initial value. Avoids `UnsetSignalValueError` on first read
* before the watched callback fires. Essential for the mutable-object observation pattern.
* @param options.equals - Optional equality function. Defaults to strict equality (`===`). Use `SKIP_EQUALITY`
* for mutable objects where the reference stays the same but internal state changes.
* @param options.guard - Optional type guard to validate values.
* @returns A read-only sensor signal.
*
* @example Tracking external values
* ```ts
* const mousePos = createSensor<{ x: number; y: number }>((set) => {
* const handler = (e: MouseEvent) => {
* set({ x: e.clientX, y: e.clientY });
* };
* window.addEventListener('mousemove', handler);
* return () => window.removeEventListener('mousemove', handler);
* });
* ```
*
* @example Observing a mutable object
* ```ts
* import { createSensor, SKIP_EQUALITY } from 'cause-effect';
*
* const el = createSensor<HTMLElement>((set) => {
* const node = document.getElementById('box')!;
* set(node);
* const obs = new MutationObserver(() => set(node));
* obs.observe(node, { attributes: true });
* return () => obs.disconnect();
* }, { value: node, equals: SKIP_EQUALITY });
* ```
*/
declare function createSensor<T extends {}>(watched: SensorCallback<T>, options?: SensorOptions<T>): Sensor<T>;
/**
* Checks if a value is a Sensor signal.
*
* @since 0.18.0
* @param value - The value to check
* @returns True if the value is a Sensor
*/
declare function isSensor<T extends {} = unknown & {}>(value: unknown): value is Sensor<T>;
export { createSensor, isSensor, type Sensor, type SensorCallback, type SensorOptions, };