UNPKG

angular-signals

Version:

Advanced Angular signals library with deep equality checking and physics-based animations

469 lines (451 loc) 14.7 kB
import * as _angular_core from '@angular/core'; import { WritableSignal, Signal } from '@angular/core'; declare function deepSignal<T>(value: T): WritableSignal<T>; declare function deepComputed<T>(computation: () => T): _angular_core.Signal<T>; interface SpringConfig { stiffness?: number; damping?: number; precision?: number; } interface SpringSignals<T extends number | number[]> { current: Signal<T>; target: WritableSignal<T>; } /** * Creates a spring animation that smoothly interpolates between values. * * @param initialValue - The initial value (number or array of numbers) * @param config - Spring configuration with stiffness, damping, and precision * @returns Object with `current` (readonly signal) and `target` (writable signal) * * @example * ```ts * const { current, target } = spring(0, { stiffness: 0.15, damping: 0.8 }); * * // Update target to animate * target.set(100); * * // Read current animated value * console.log(current()); * ``` */ declare function spring(initialValue: number, config?: SpringConfig): SpringSignals<number>; declare function spring(initialValue: number[], config?: SpringConfig): SpringSignals<number[]>; type InterpolateFunction<T> = (from: T, to: T) => (t: number) => T; interface TweenOptions<T extends number | number[]> { duration: number; delay?: number; easing?: (t: number) => number; interpolate?: InterpolateFunction<T>; } interface TweenSignals<T extends number | number[]> { current: Signal<T>; target: WritableSignal<T>; } /** * Creates a tween animation that smoothly interpolates between values over a fixed duration. * * @param initialValue - The initial value (number or array of numbers) * @param options - Tween configuration with duration, delay, easing function, and interpolation * @returns Object with `current` (readonly signal) and `target` (writable signal) * * @example * ```ts * // Basic usage * const { current, target } = tween(0, { * duration: 1000, * delay: 500, * easing: (t) => t * t * }); * * // With custom interpolation (curried function) * const { current, target } = tween(0, { * duration: 1000, * interpolate: (from, to) => (t) => from + (to - from) * t * }); * * // Update target to animate * target.set(100); * * // Read current animated value * console.log(current()); * ``` */ declare function tween(initialValue: number, options: TweenOptions<number>): TweenSignals<number>; declare function tween(initialValue: number[], options: TweenOptions<number[]>): TweenSignals<number[]>; /** * Creates a signal that tracks the previous value of another signal. * * @param source - The signal to track * @returns A signal containing the previous value (undefined on first read) * * @example * ```ts * const count = signal(0); * const prevCount = usePrevious(count); * * console.log(prevCount()); // undefined * count.set(1); * console.log(prevCount()); // 0 * count.set(2); * console.log(prevCount()); // 1 * ``` */ declare function usePrevious<T>(source: Signal<T>): Signal<T | undefined>; /** * Return type for the useToggle function. */ interface ToggleReturn { /** The current boolean value */ value: Signal<boolean>; /** Toggle the value */ toggle: () => void; /** Set value to true */ setTrue: () => void; /** Set value to false */ setFalse: () => void; } /** * Creates a boolean signal with convenient toggle methods. * * @param initial - Initial boolean value (default: false) * @returns Object with value signal and toggle methods * * @example * ```ts * const modal = useToggle(false); * * console.log(modal.value()); // false * modal.toggle(); * console.log(modal.value()); // true * modal.setFalse(); * console.log(modal.value()); // false * ``` */ declare function useToggle(initial?: boolean): ToggleReturn; /** * Return type for the useCounter function. */ interface CounterReturn { /** The current count value */ count: Signal<number>; /** Increment the counter by step (default: 1) */ increment: (step?: number) => void; /** Decrement the counter by step (default: 1) */ decrement: (step?: number) => void; /** Reset the counter to initial or specified value */ reset: (value?: number) => void; /** Set the counter to a specific value */ set: (value: number) => void; } /** * Creates a counter signal with increment/decrement methods and optional bounds. * * @param initial - Initial count value (default: 0) * @param min - Minimum allowed value (default: -Infinity) * @param max - Maximum allowed value (default: Infinity) * @returns Object with count signal and manipulation methods * * @example * ```ts * const counter = useCounter(0, 0, 10); * * console.log(counter.count()); // 0 * counter.increment(); * console.log(counter.count()); // 1 * counter.increment(5); * console.log(counter.count()); // 6 * counter.increment(10); * console.log(counter.count()); // 10 (clamped to max) * counter.reset(); * console.log(counter.count()); // 0 * ``` */ declare function useCounter(initial?: number, min?: number, max?: number): CounterReturn; /** * Return type for the useArray function. */ interface ArrayReturn<T> { /** The current array value */ items: Signal<readonly T[]>; /** Add items to the end of the array */ push: (...items: T[]) => void; /** Remove and return the last item */ pop: () => T | undefined; /** Remove and return the first item */ shift: () => T | undefined; /** Add items to the beginning of the array */ unshift: (...items: T[]) => void; /** Filter items based on predicate */ filter: (predicate: (item: T, index: number) => boolean) => void; /** Map items to new values */ map: <U>(fn: (item: T, index: number) => U) => void; /** Remove all items */ clear: () => void; /** Remove item at specific index */ remove: (index: number) => void; /** Insert item at specific index */ insert: (index: number, item: T) => void; /** Replace the entire array */ set: (items: T[]) => void; /** Find first item matching predicate */ find: (predicate: (item: T) => boolean) => T | undefined; /** Find index of first item matching predicate */ findIndex: (predicate: (item: T) => boolean) => number; } /** * Creates an array signal with convenient manipulation methods. * All operations return new arrays (immutable). * * @param initial - Initial array value (default: []) * @returns Object with items signal and array manipulation methods * * @example * ```ts * const todos = useArray<string>(['Buy milk', 'Walk dog']); * * console.log(todos.items()); // ['Buy milk', 'Walk dog'] * todos.push('Clean room'); * console.log(todos.items()); // ['Buy milk', 'Walk dog', 'Clean room'] * todos.remove(0); * console.log(todos.items()); // ['Walk dog', 'Clean room'] * todos.clear(); * console.log(todos.items()); // [] * ``` */ declare function useArray<T>(initial?: T[]): ArrayReturn<T>; /** * Configuration options for debouncing. */ interface DebounceOptions { /** Delay in milliseconds */ delay: number; /** Execute on the leading edge (default: false) */ leading?: boolean; /** Execute on the trailing edge (default: true) */ trailing?: boolean; } /** * Creates a debounced version of a signal that delays updates. * * @param source - The signal to debounce * @param options - Debounce configuration * @returns A debounced signal * * @example * ```ts * const search = signal(''); * const debouncedSearch = useDebounce(search, { delay: 300 }); * * search.set('hello'); // debouncedSearch updates after 300ms * ``` */ declare function useDebounce<T>(source: Signal<T>, options: DebounceOptions): Signal<T>; /** * Configuration options for throttling. */ interface ThrottleOptions { /** Delay in milliseconds */ delay: number; /** Execute on the leading edge (default: true) */ leading?: boolean; /** Execute on the trailing edge (default: false) */ trailing?: boolean; } /** * Creates a throttled version of a signal that limits update frequency. * * @param source - The signal to throttle * @param options - Throttle configuration * @returns A throttled signal * * @example * ```ts * const scrollY = signal(0); * const throttledScrollY = useThrottle(scrollY, { delay: 100 }); * * // scrollY updates frequently, but throttledScrollY updates at most once per 100ms * ``` */ declare function useThrottle<T>(source: Signal<T>, options: ThrottleOptions): Signal<T>; /** * Return type for the useInterval function. */ interface IntervalReturn { /** Number of times the interval has executed */ count: Signal<number>; /** Whether the interval is currently active */ isActive: Signal<boolean>; /** Pause the interval */ pause: () => void; /** Resume the interval */ resume: () => void; /** Reset the count and restart the interval */ reset: () => void; } /** * Creates an interval that executes a callback repeatedly with pause/resume control. * * @param callback - Function to execute on each interval * @param delay - Delay in milliseconds (or signal of delay) * @returns Object with control methods and state signals * * @example * ```ts * const timer = useInterval(() => { * console.log('Tick'); * }, 1000); * * console.log(timer.count()); // Number of ticks * timer.pause(); // Pause the interval * timer.resume(); // Resume the interval * timer.reset(); // Reset count and restart * ``` */ declare function useInterval(callback: () => void, delay: number | Signal<number>): IntervalReturn; /** * Return type for the useTimeout function. */ interface TimeoutReturn { /** Whether the timeout has completed */ isReady: Signal<boolean>; /** Whether the timeout is currently pending */ isPending: Signal<boolean>; /** Cancel the timeout */ cancel: () => void; /** Reset and restart the timeout */ reset: () => void; } /** * Creates a timeout that executes a callback after a delay with cancel/reset control. * * @param callback - Function to execute after timeout * @param delay - Delay in milliseconds (or signal of delay) * @returns Object with control methods and state signals * * @example * ```ts * const timeout = useTimeout(() => { * console.log('Timeout completed!'); * }, 3000); * * effect(() => { * if (timeout.isReady()) { * console.log('Ready!'); * } * }); * * timeout.cancel(); // Cancel the timeout * timeout.reset(); // Reset and restart * ``` */ declare function useTimeout(callback: () => void, delay: number | Signal<number>): TimeoutReturn; /** * Configuration options for useNow. */ interface NowOptions { /** Update interval in milliseconds (default: 1000) */ interval?: number; } /** * Creates a signal that contains the current Date, updating at a specified interval. * * @param options - Configuration options * @returns A signal containing the current Date * * @example * ```ts * const now = useNow({ interval: 1000 }); * * effect(() => { * console.log('Current time:', now().toLocaleTimeString()); * }); * ``` */ declare function useNow(options?: NowOptions): Signal<Date>; /** * Creates a signal that tracks whether a media query matches. * * @param query - CSS media query string or signal of query * @returns A signal indicating if the media query matches * * @example * ```ts * const isMobile = useMediaQuery('(max-width: 768px)'); * const isDark = useMediaQuery('(prefers-color-scheme: dark)'); * * effect(() => { * console.log('Is mobile:', isMobile()); * console.log('Dark mode:', isDark()); * }); * ``` */ declare function useMediaQuery(query: string | Signal<string>): Signal<boolean>; /** * Attaches an event listener to a target with automatic cleanup. * * @param target - Event target (Window, Document, HTMLElement, or signal of element) * @param event - Event name * @param handler - Event handler function * @param options - AddEventListener options * * @example * ```ts * // Listen to window resize * useEventListener(window, 'resize', () => { * console.log('Window resized'); * }); * * // Listen to element clicks * const button = signal<HTMLElement | null>(null); * useEventListener(button, 'click', (event) => { * console.log('Button clicked', event); * }); * ``` */ declare function useEventListener<K extends keyof WindowEventMap>(target: Window, event: K, handler: (event: WindowEventMap[K]) => void, options?: AddEventListenerOptions): void; declare function useEventListener<K extends keyof DocumentEventMap>(target: Document, event: K, handler: (event: DocumentEventMap[K]) => void, options?: AddEventListenerOptions): void; declare function useEventListener<K extends keyof HTMLElementEventMap>(target: HTMLElement | Signal<HTMLElement | null>, event: K, handler: (event: HTMLElementEventMap[K]) => void, options?: AddEventListenerOptions): void; /** * Return type for storage functions. */ interface StorageReturn<T> { /** The stored value */ value: WritableSignal<T>; /** Remove the value from storage */ remove: () => void; } /** * Creates a signal synced with localStorage. * * @param key - Storage key * @param initialValue - Initial value if key doesn't exist * @returns Object with value signal and remove method * * @example * ```ts * const theme = useLocalStorage('theme', 'light'); * * theme.value.set('dark'); // Persists to localStorage * console.log(theme.value()); // 'dark' * theme.remove(); // Removes from localStorage * ``` */ declare function useLocalStorage<T>(key: string, initialValue: T): StorageReturn<T>; /** * Creates a signal synced with sessionStorage. * * @param key - Storage key * @param initialValue - Initial value if key doesn't exist * @returns Object with value signal and remove method * * @example * ```ts * const sessionData = useSessionStorage('user', { name: 'Guest' }); * * sessionData.value.set({ name: 'John' }); // Persists to sessionStorage * ``` */ declare function useSessionStorage<T>(key: string, initialValue: T): StorageReturn<T>; export { deepComputed, deepSignal, spring, tween, useArray, useCounter, useDebounce, useEventListener, useInterval, useLocalStorage, useMediaQuery, useNow, usePrevious, useSessionStorage, useThrottle, useTimeout, useToggle }; export type { ArrayReturn, CounterReturn, DebounceOptions, InterpolateFunction, IntervalReturn, NowOptions, SpringConfig, SpringSignals, StorageReturn, ThrottleOptions, TimeoutReturn, ToggleReturn, TweenOptions, TweenSignals };