All public functions, types, and exports.
Mount Signet.js onto a root element using a shared global store. All instances created via Signet() on the same page share the same global store object, accessible via .store().
| Parameter | Type | Description |
|---|---|---|
| rootEl | Element | The root DOM element to bind. |
| dataFn | () => Object (optional) | Function returning initial data. Plain values → signals, getters → computeds. |
Returns a SignetApp.
import Signet from 'signet.js';
const app = Signet(document.getElementById('app'), () => ({
count: 0,
get doubled() { return this.count * 2; },
}));
// Add to the global store (available to all Signet() instances)
app.store({ theme: 'dark', locale: 'en' });
// Later, tear down
app.unmount();
Create an app builder (petite-vue style). Accepts a plain object or a factory function. Call .store(), .directive(), and finally .mount() to activate.
| Parameter | Type | Description |
|---|---|---|
| data | Object | () => Object | Initial app data. Getters become computeds, methods are auto-bound. |
Returns an AppBuilder.
import { createApp } from 'signet.js';
createApp({
name: 'Alice',
count: 0,
get greeting() { return 'Hi, ' + this.name; },
increment() { this.count = this.count + 1; },
})
.store({ siteName: 'My App' })
.directive('focus', ({ el }) => { el.focus(); })
.mount('#app');
Returned by createApp(). All methods except .mount() return this for chaining.
Register shared global state. Properties are added to the prototype of all scopes, so any directive expression can read them. Local scope properties shadow store properties of the same name.
createApp({ count: 0 })
.store({
theme: 'dark',
user: { name: 'Alice', role: 'admin' },
})
.mount('#app');
Register a custom directive available as js-{name}. The handler receives a DirectiveContext and may return a cleanup function.
createApp({ tooltip: '' })
.directive('tooltip', ({ el, exp, scope, effect }) => {
const dispose = effect(() => {
el.setAttribute('title', evaluate(exp, scope));
});
return dispose;
})
.mount('#app');
Activate the app by walking the root element. Accepts an Element or a CSS selector string. Returns a SignetApp.
const app = createApp({ count: 0 }).mount('#app');
// or
const app = createApp({ count: 0 }).mount(document.body);
Returned by .mount() and Signet(). Provides post-mount control over the app.
| Property / Method | Type | Description |
|---|---|---|
| .store(obj) | (obj: Object) => void | Add more properties to the global store after mounting. New keys are merged into the scope prototype. |
| .directive(name, fn) | (name: string, fn: DirectiveHandler) => void | Register a custom directive after mounting. Available in future walks (e.g., dynamically added elements). |
| .unmount() | () => void | Dispose all reactive effects recursively, depth-first. Cleans up all signals and event listeners. |
| .scope | Object | The reactive scope object. Useful for debugging or programmatically reading/writing state. |
const app = createApp({ count: 0 }).mount('#app');
// Read current state (signals need .value)
console.log(app.scope.count.value); // 0
// Update state programmatically
app.scope.count.value = 42;
// Add more store data after mount
app.store({ newProp: 'hello' });
// Tear down
app.unmount();
The object passed to custom directive handlers. Use its properties to access the element, the expression, and the reactive environment.
| Property | Type | Description |
|---|---|---|
| el | Element | The DOM element bearing this directive. |
| exp | string | The raw expression string from the attribute value. |
| arg | string | null | The colon argument (e.g., "click" for js-on:click). |
| modifiers | string[] | List of dot-separated modifiers (e.g., ["prevent", "once"]). |
| scope | Object | The reactive scope object. Contains signals and computed values. Use evaluate(exp, scope) to resolve the expression. |
| effect | function | The effect() function from @preact/signals-core. Use to create reactive subscriptions. The returned disposer is registered as a cleanup function automatically. |
// Full custom directive example
.directive('intersect', ({ el, exp, modifiers, scope, effect }) => {
const once = modifiers.includes('once');
const callback = evaluate(exp, scope);
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
callback(entry);
if (once) observer.disconnect();
}
});
});
observer.observe(el);
// Return a cleanup function
return () => observer.disconnect();
})
Named exports from both entry points:
| Export | Description |
|---|---|
| default (Signet) | The Signet(el, dataFn) factory. |
| createApp | The createApp(data) builder. |
| setDevMode | Enable or disable dev-mode property-resolution warnings. Call before mounting. |
| resolve | Safe dot/bracket path resolver: resolve('user.profile.name', scope). Returns undefined if any segment is null. |
| evaluate | The expression evaluator: evaluate(expr, scope). Only exported from the default (CSP-safe) entry point. |
| Export | Description |
|---|---|
| signal(value) | Create a mutable reactive value. Access via .value. |
| computed(fn) | Create a derived/read-only signal that re-computes when dependencies change. |
| effect(fn) | Run a side-effect function and re-run it whenever signals it reads change. Returns a disposer. |
| batch(fn) | Group multiple signal writes so all effects run once after all writes are done. |
import { setDevMode } from 'signet.js';
// Enable warnings for undefined property access in expressions
setDevMode(true);
createApp({ count: 0 })
// In dev mode: accessing `oops` would log: [Signet] Cannot read 'oops'...
.mount('#app');
import { resolve } from 'signet.js';
const scope = { user: { profile: { name: 'Alice' } } };
resolve('user.profile.name', scope); // 'Alice'
resolve('user.missing.deep', scope); // undefined (no throw)
resolve('list[2]', { list: ['a','b','c'] }); // 'c'
Available in every directive expression as globals:
<!-- Create a new signal inside an expression -->
<div js-scope="{ items: $signal([]) }">...</div>
<!-- Batch multiple updates in an event handler -->
<button js-on:click="$batch(() => { count = 0; name = '' })">Reset all</button>
// Also available as named imports for use outside Signet
import { signal, computed, effect, batch } from 'signet.js';