๐งฉ Signux
Minimal reactive primitives for building fine-grained reactivity in JavaScript and TypeScript.
Composable, testable, and framework-agnostic.
โจ Features
- โ
state
, computed
, and event
primitives
- โ
pipe(...)
for functional reactive composition
- โ
Built-in async handling via
stateAsync
and mapAsync
- โ
Small, fast, and tree-shakable
- โ
Type-safe and JSDoc-documented
๐ฆ Installation
bun add signux
npm install signux
๐ Usage
Reactive state
import { state } from "signux";
const counter = state(0);
console.log(counter());
counter
.on(
{ subscribe: (fn) => setInterval(() => fn(1), 1000) },
(prev, n) => prev + n,
)
.create();
Derived state (computed
)
import { computed } from "signux";
const first = state("Ada");
const last = state("Lovelace");
const fullName = computed(() => \`\${first()} \${last()}\`);
console.log(fullName()); // Ada Lovelace
Events
import { event } from "signux";
const click = event<MouseEvent>();
click.subscribe((e) => console.log("Clicked!", e));
๐งช Async support
stateAsync
import { stateAsync } from "signux";
const user = stateAsync(fetchUser);
user.fetch(1);
const { loading, data, error } = user();
mapAsync
operator
import { event } from "signux";
import { mapAsync } from "signux/operators";
const search = event<string>();
const results = search.pipe(mapAsync((query) => fetchResults(query))).toState();
๐งฉ Operators
Operators are chainable transformations for events and state:
import { map, filter, debounce } from "signux/operators";
const search = event<string>();
const trimmed = search.pipe(
map((s) => s.trim()),
filter((s) => s.length > 2),
debounce(300),
);
Available operators:
map
filter
debounce
merge
mapAsync
๐ API Summary
state<T>()
โ create mutable reactive state
computed<T>()
โ create derived state that auto-tracks dependencies
event<T>()
โ create an event emitter that can be observed
stateAsync(fetcher)
โ reactive wrapper for async operations
.pipe(...)
โ apply transformation operators
effect(fn)
โ run a reactive side-effect
๐ Type safety
All primitives and operators are fully typed and documented using JSDoc.
IntelliSense works out of the box in TypeScript and modern editors.
No proxies. No magic. Just simple reactive building blocks you control.
๐ License
MIT