UNPKG

svelte-interval-rune

Version:

Svelte 5 utility for creating intervals

309 lines (215 loc) 9.69 kB
# Svelte Interval A comprehensive Svelte utility package for managing intervals with reactive durations, synchronization, and advanced control features. This package provides convenient classes and functions for creating and controlling `setInterval` operations with full reactivity support. **Features:** - **Core Interval Management:** Basic reactive interval functionality with pause/resume/stop controls - **Limited Intervals:** Automatically complete after a specified number of ticks - **Interval Synchronization:** Sync multiple intervals to tick together at the fastest interval's pace - **Reactive Durations:** Dynamically change interval timings based on Svelte's `$state` - **Complete Lifecycle Control:** Pause, resume, stop, and restart intervals - **Tick Counting:** Track how many times intervals have fired - **Immediate Start Option:** Optionally create intervals immediately upon initialization - **Automatic Cleanup:** Handles `clearInterval` when durations change or components unmount - **Lazy Initialization:** Intervals only start when accessed (unless `immediate: true`) ## Installation ```bash npm install svelte-interval-rune ``` ## Basic Usage ### Creating a Simple Interval ```svelte <script> import { Interval } from 'svelte-interval-rune'; const timer = new Interval(1000); </script> <p>Time: {timer.current.toLocaleTimeString()}</p> <p>Ticks: {timer.tickCount}</p> ``` ### Immediate vs Lazy Initialization ```svelte <script> import { Interval } from 'svelte-interval-rune'; // Lazy (default) - starts when accessed const lazyTimer = new Interval(1000); // Immediate - starts right away const immediateTimer = new Interval(1000, { immediate: true }); </script> <p>Lazy: {lazyTimer.current.toLocaleTimeString()}</p> <p>Immediate: {immediateTimer.current.toLocaleTimeString()}</p> ``` ### Reactive Duration ```svelte <script> import { Interval } from 'svelte-interval-rune'; let speed = $state(1000); const timer = new Interval(() => speed); </script> <p>Duration: {timer.duration}ms | Ticks: {timer.tickCount}</p> <button onclick={() => speed = 500}>Fast</button> <button onclick={() => speed = 2000}>Slow</button> ``` ## Interval Control ### Pause, Resume, and Stop ```svelte <script> import { Interval } from 'svelte-interval-rune'; const timer = new Interval(1000); </script> <p>Ticks: {timer.tickCount} | Status: {timer.isActive ? 'Running' : timer.isStopped ? 'Stopped' : 'Paused'}</p> <button onclick={() => timer.pause()}>Pause</button> <button onclick={() => timer.resume()}>Resume</button> <button onclick={() => timer.resume(true)}>Resume Immediate</button> <button onclick={() => timer.stop()}>Stop</button> ``` **Key Differences:** - **Pause:** Temporarily stops ticking but keeps the interval running internally - **Stop:** Completely destroys the interval and resets state - **Resume:** Continues from where it was paused - **Resume(true):** Immediately ticks and resets timing cycle ## Limited Intervals Use `LimitedInterval` when you need an interval that automatically stops after a specific number of ticks. ```svelte <script> import { LimitedInterval } from 'svelte-interval-rune'; const timer = new LimitedInterval(500, 10); // 500ms interval, stops after 10 ticks </script> <p>Ticks: {timer.tickCount} / {timer.maxTicks}</p> <p>Remaining: {timer.remainingTicks}</p> <p>Completed: {timer.isCompleted}</p> <button onclick={() => timer.reset()}>Reset</button> <input type="number" bind:value={timer.maxTicks} min="1" /> ``` ### LimitedInterval Features - **Automatic Completion:** Stops automatically after reaching `maxTicks` - **Reset Functionality:** Use `reset()` to continue from current tick count - **Dynamic Limits:** Change `maxTicks` at runtime - **Remaining Ticks:** Track progress with `remainingTicks` - **Completion State:** Check `isCompleted` status ## Interval Synchronization The `sync()` function allows multiple intervals to tick together at the pace of the fastest interval. ```svelte <script> import { Interval, LimitedInterval, sync } from 'svelte-interval-rune'; const timer1 = new Interval(1000); // 1 second const timer2 = new Interval(500); // 500ms (will be leader - fastest) const timer3 = new LimitedInterval(750, 5); // 750ms, 5 ticks max const controller = sync(timer1, timer2, timer3); </script> <p>Leader: {controller.leader.duration}ms | Sync: {controller.isSynced ? 'On' : 'Off'}</p> <p>Timer1: {timer1.tickCount} | Timer2: {timer2.tickCount} | Timer3: {timer3.tickCount}</p> <button onclick={() => controller.enable()}>Enable Sync</button> <button onclick={() => controller.disable()}>Disable Sync</button> ``` ### Sync Behavior - **Leader Selection:** The fastest interval (shortest duration) becomes the leader - **Synchronized Ticking:** All intervals tick together at the leader's pace - **Individual State:** Each interval maintains its own pause/active state - **Leader Completion:** When the leader completes (if it's a LimitedInterval), sync stops - **Restoration:** When sync is disabled, intervals return to their individual timing ### Advanced Sync Example ```svelte <script> import { Interval, LimitedInterval, sync } from 'svelte-interval-rune'; const fast = new Interval(100); // Fast timer const limited = new LimitedInterval(200, 3); // Limited interval const controller = sync(fast, limited); </script> <p>Fast: {fast.tickCount} | Limited: {limited.tickCount}/{limited.maxTicks}</p> <p>Leader: {controller.leader.duration}ms | Completed: {limited.isCompleted}</p> <button onclick={() => controller.enable()}>Start Sync</button> <button onclick={() => limited.reset()}>Reset Limited</button> ``` ## API Reference ### Interval Class #### Constructor ```typescript new Interval(duration: number | (() => number), options?: IntervalOptions) ``` **Parameters:** - `duration` - Static number or reactive function returning interval duration in milliseconds - `options.immediate?` - If `true`, starts interval immediately. Default: `false` #### Properties - `current: Date` - Gets current time and auto-starts interval - `duration: number` - Gets or sets the interval duration - `isActive: boolean` - Whether the interval is currently active (not paused/stopped) - `isStopped: boolean` - Whether the interval has been completely stopped - `tickCount: number` - Number of times the interval has fired (auto-starts interval) #### Methods - `pause(): void` - Pauses the interval (can be resumed) - `resume(immediate?: boolean): void` - Resumes the interval, optionally with immediate tick - `stop(): void` - Completely stops and cleans up the interval - `[Symbol.dispose](): void` - Automatic cleanup (works with `using`) ### LimitedInterval Class Extends `Interval` with automatic completion after N ticks. #### Constructor ```typescript new LimitedInterval(duration: number | (() => number), maxTicks: number, options?: IntervalOptions) ``` **Additional Parameters:** - `maxTicks` - Number of ticks before auto-completion #### Additional Properties - `maxTicks: number` - Gets or sets the maximum tick limit - `isCompleted: boolean` - Whether the interval has reached its tick limit - `remainingTicks: number` - Number of ticks remaining before completion #### Additional Methods - `reset(): void` - Resets completion state and resumes from current tick count ### sync() Function #### Signature ```typescript function sync(...intervals: Interval[]): SyncController; ``` **Parameters:** - `...intervals` - One or more Interval or LimitedInterval instances to synchronize #### Returns: SyncController ```typescript interface SyncController { enable(): void; // Start synchronization disable(): void; // Stop synchronization and restore individual timing isSynced: boolean; // Whether sync is currently active leader: Interval; // The fastest interval driving synchronization } ``` ### IntervalOptions ```typescript interface IntervalOptions { immediate?: boolean; // Start interval immediately on construction } ``` ## Advanced Patterns ### Custom Timer with Reset ```svelte <script> import { Interval } from 'svelte-interval-rune'; let duration = $state(1000); let timer = $state(new Interval(() => duration)); function resetTimer() { timer.stop(); timer = new Interval(() => duration); } </script> <p>Ticks: {timer.tickCount} | Duration: {duration}ms</p> <button onclick={() => duration = 500}>Fast</button> <button onclick={() => resetTimer()}>Reset</button> ``` ### Countdown Timer ```svelte <script> import { LimitedInterval } from 'svelte-interval-rune'; let countdown = new LimitedInterval(1000, 10); // 10 second countdown </script> <p>{countdown.isCompleted ? 'Time\'s Up!' : `${countdown.remainingTicks}s left`}</p> <button onclick={() => countdown.current}>Start</button> <button onclick={() => countdown.reset()}>Reset</button> ``` ## Performance Notes - **Lazy Initialization:** Intervals only start when `current` or `tickCount` is first accessed (unless `immediate: true`) - **Automatic Cleanup:** All intervals automatically clean up when components unmount - **Memory Efficient:** Stopped intervals are fully cleaned up and garbage collected - **Sync Overhead:** Minimal overhead when syncing intervals - leader drives all timing ## Bundle Size - **Interval:** ~475B (minified + brotlied) - **LimitedInterval:** ~681B (minified + brotlied) - **sync:** ~289B (minified + brotlied) - **Interval + LimitedInterval:** ~684B (minified + brotlied) - **Interval + sync:** ~679B (minified + brotlied) - **LimitedInterval + sync:** ~877B (minified + brotlied) - **Total Package:** ~876B for all features