preact-sigma 2.2.3 → 2.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/index.d.mts +36 -13
- package/dist/index.mjs +34 -6
- package/docs/context.md +3 -1
- package/examples/sigma-target.ts +26 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -43,5 +43,5 @@ console.log(counter.doubled); // 2
|
|
|
43
43
|
- Concepts, lifecycle, invariants, and API selection live in [`docs/context.md`](./docs/context.md).
|
|
44
44
|
- Quick-start usage lives in [`examples/basic-counter.ts`](./examples/basic-counter.ts).
|
|
45
45
|
- An advanced end-to-end example lives in [`examples/command-palette.tsx`](./examples/command-palette.tsx).
|
|
46
|
-
- Focused examples for non-obvious APIs live in [`examples/async-commit.ts`](./examples/async-commit.ts), [`examples/observe-and-restore.ts`](./examples/observe-and-restore.ts), [`examples/
|
|
46
|
+
- Focused examples for non-obvious APIs live in [`examples/async-commit.ts`](./examples/async-commit.ts), [`examples/observe-and-restore.ts`](./examples/observe-and-restore.ts), [`examples/setup-act.ts`](./examples/setup-act.ts), [`examples/sigma-target.ts`](./examples/sigma-target.ts), and [`examples/signal-access.ts`](./examples/signal-access.ts).
|
|
47
47
|
- Exact exported signatures live in `dist/index.d.mts` after `pnpm build`.
|
package/dist/index.d.mts
CHANGED
|
@@ -160,7 +160,7 @@ declare function replaceState<T extends AnySigmaState>(publicInstance: T, nextSt
|
|
|
160
160
|
//#endregion
|
|
161
161
|
//#region src/framework.d.ts
|
|
162
162
|
/** Checks whether a value is an instance created by a configured sigma type. */
|
|
163
|
-
declare function isSigmaState(value:
|
|
163
|
+
declare function isSigmaState(value: object): value is AnySigmaState;
|
|
164
164
|
/**
|
|
165
165
|
* Creates a standalone tracked query helper with the same signature as `fn`.
|
|
166
166
|
*
|
|
@@ -272,22 +272,45 @@ interface SigmaType<TState extends AnyState, TEvents extends AnyEvents, TDefault
|
|
|
272
272
|
}
|
|
273
273
|
//#endregion
|
|
274
274
|
//#region src/listener.d.ts
|
|
275
|
-
type
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
}
|
|
275
|
+
type InferEventMap<TTarget extends EventTarget> = TTarget extends {
|
|
276
|
+
[sigmaEventsBrand]: infer TEvents extends AnyEvents;
|
|
277
|
+
} ? TEvents : TTarget extends Window ? WindowEventMap : TTarget extends Document ? DocumentEventMap : TTarget extends HTMLBodyElement ? HTMLBodyElementEventMap : TTarget extends HTMLMediaElement ? HTMLMediaElementEventMap : TTarget extends HTMLElement ? HTMLElementEventMap : TTarget extends SVGSVGElement ? SVGSVGElementEventMap : TTarget extends SVGElement ? SVGElementEventMap : never;
|
|
278
|
+
type InferListenerArgs<TEvents extends object, TTarget extends EventTarget, TEvent extends string> = [(TEvent extends keyof TEvents ? TEvents[TEvent] : never) extends infer TPayload ? TTarget extends {
|
|
279
|
+
[sigmaEventsBrand]: TEvents;
|
|
280
|
+
} ? [TPayload] extends [never] ? never : [TPayload] extends [void] ? undefined : TPayload : ([TPayload] extends [never] ? CustomEvent : Extract<TPayload, Event>) & {
|
|
281
|
+
readonly currentTarget: TTarget;
|
|
282
|
+
} : never];
|
|
283
|
+
/** Infers the listener callback shape for a target and event name. Sigma states receive payloads directly, while DOM targets receive typed events. */
|
|
284
|
+
type InferListener<TTarget extends EventTarget, TEvent extends string = string> = InferEventMap<TTarget> extends infer TEvents extends object ? ((...args: InferListenerArgs<TEvents, TTarget, TEvent>) => void) & {
|
|
285
|
+
__eventType?: TEvent;
|
|
286
|
+
} : never;
|
|
281
287
|
/** Infers the event names accepted by `listen(...)` or `useListener(...)` for a target. */
|
|
282
288
|
type InferEventType<TTarget extends EventTarget> = (InferListener<TTarget> extends {
|
|
283
289
|
__eventType?: infer TEvent;
|
|
284
290
|
} ? string & TEvent : never) | (string & {});
|
|
285
|
-
/**
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
291
|
+
/**
|
|
292
|
+
* A standalone typed event hub with `emit(...)` and `on(...)` methods and full
|
|
293
|
+
* `EventTarget`, `listen(...)`, and `useListener(...)` compatibility.
|
|
294
|
+
*/
|
|
295
|
+
declare class SigmaTarget<TEvents extends AnyEvents = {}> extends EventTarget {
|
|
296
|
+
readonly [sigmaEventsBrand]: TEvents;
|
|
297
|
+
/**
|
|
298
|
+
* Emits a typed event from the hub.
|
|
299
|
+
*
|
|
300
|
+
* Void events dispatch a plain `Event`. Payload events dispatch a
|
|
301
|
+
* `CustomEvent` whose `detail` holds the payload.
|
|
302
|
+
*/
|
|
303
|
+
emit<TEvent extends string & keyof TEvents>(name: TEvent, ...args: [TEvents[TEvent]] extends [void] ? [] : [payload: TEvents[TEvent]]): void;
|
|
304
|
+
/**
|
|
305
|
+
* Registers a typed event listener and returns an unsubscribe function.
|
|
306
|
+
*
|
|
307
|
+
* Payload events pass their payload directly to the listener. Void events
|
|
308
|
+
* call the listener with no arguments.
|
|
309
|
+
*/
|
|
310
|
+
on<TEvent extends string & keyof TEvents>(name: TEvent, listener: (...args: InferListenerArgs<TEvents, this, TEvent>) => void): () => void;
|
|
311
|
+
}
|
|
289
312
|
/** Adds a listener to a sigma state or DOM target and returns a cleanup function that removes it. */
|
|
290
|
-
declare function listen<TTarget extends EventTarget, TEvent extends InferEventType<TTarget>>(target: TTarget, name: TEvent,
|
|
313
|
+
declare function listen<TTarget extends EventTarget, TEvent extends InferEventType<TTarget>>(target: TTarget, name: TEvent, listener: InferListener<TTarget, TEvent>): () => void;
|
|
291
314
|
//#endregion
|
|
292
315
|
//#region src/hooks.d.ts
|
|
293
316
|
/**
|
|
@@ -306,4 +329,4 @@ declare function useSigma<T extends AnySigmaState>(create: () => T, setupArgs?:
|
|
|
306
329
|
*/
|
|
307
330
|
declare function useListener<TTarget extends EventTarget | AnySigmaState, TEvent extends InferEventType<TTarget>>(target: TTarget | null, name: TEvent, listener: InferListener<TTarget, TEvent>): void;
|
|
308
331
|
//#endregion
|
|
309
|
-
export { type AnyDefaultState, type AnyEvents, type AnyResource, type AnySigmaState, type AnySigmaStateWithEvents, type AnyState, InferEventType, InferListener, type InferSetupArgs, type SigmaObserveChange, type SigmaObserveOptions, type SigmaRef, type SigmaState, SigmaType, action, batch, computed, effect, freeze, immerable, isSigmaState, listen, query, replaceState, setAutoFreeze, snapshot, untracked, useListener, useSigma };
|
|
332
|
+
export { type AnyDefaultState, type AnyEvents, type AnyResource, type AnySigmaState, type AnySigmaStateWithEvents, type AnyState, InferEventType, InferListener, type InferSetupArgs, type SigmaObserveChange, type SigmaObserveOptions, type SigmaRef, type SigmaState, SigmaTarget, SigmaType, action, batch, computed, effect, freeze, immerable, isSigmaState, listen, query, replaceState, setAutoFreeze, snapshot, untracked, useListener, useSigma };
|
package/dist/index.mjs
CHANGED
|
@@ -541,7 +541,7 @@ Object.defineProperty(Sigma.prototype, sigmaStateBrand, { value: true });
|
|
|
541
541
|
//#region src/framework.ts
|
|
542
542
|
/** Checks whether a value is an instance created by a configured sigma type. */
|
|
543
543
|
function isSigmaState(value) {
|
|
544
|
-
return Boolean(value
|
|
544
|
+
return Boolean(value[sigmaStateBrand]);
|
|
545
545
|
}
|
|
546
546
|
/**
|
|
547
547
|
* Creates a standalone tracked query helper with the same signature as `fn`.
|
|
@@ -629,12 +629,40 @@ var SigmaType = class extends Function {
|
|
|
629
629
|
};
|
|
630
630
|
//#endregion
|
|
631
631
|
//#region src/listener.ts
|
|
632
|
+
/**
|
|
633
|
+
* A standalone typed event hub with `emit(...)` and `on(...)` methods and full
|
|
634
|
+
* `EventTarget`, `listen(...)`, and `useListener(...)` compatibility.
|
|
635
|
+
*/
|
|
636
|
+
var SigmaTarget = class extends EventTarget {
|
|
637
|
+
/**
|
|
638
|
+
* Emits a typed event from the hub.
|
|
639
|
+
*
|
|
640
|
+
* Void events dispatch a plain `Event`. Payload events dispatch a
|
|
641
|
+
* `CustomEvent` whose `detail` holds the payload.
|
|
642
|
+
*/
|
|
643
|
+
emit(name, ...args) {
|
|
644
|
+
this.dispatchEvent(args.length === 0 ? new Event(name) : new CustomEvent(name, { detail: args[0] }));
|
|
645
|
+
}
|
|
646
|
+
/**
|
|
647
|
+
* Registers a typed event listener and returns an unsubscribe function.
|
|
648
|
+
*
|
|
649
|
+
* Payload events pass their payload directly to the listener. Void events
|
|
650
|
+
* call the listener with no arguments.
|
|
651
|
+
*/
|
|
652
|
+
on(name, listener) {
|
|
653
|
+
const adapter = (event) => listener(event.detail);
|
|
654
|
+
this.addEventListener(name, adapter);
|
|
655
|
+
return () => {
|
|
656
|
+
this.removeEventListener(name, adapter);
|
|
657
|
+
};
|
|
658
|
+
}
|
|
659
|
+
};
|
|
632
660
|
/** Adds a listener to a sigma state or DOM target and returns a cleanup function that removes it. */
|
|
633
|
-
function listen(target, name,
|
|
634
|
-
const
|
|
635
|
-
target.addEventListener(name,
|
|
661
|
+
function listen(target, name, listener) {
|
|
662
|
+
const adapter = isSigmaState(target) || target instanceof SigmaTarget ? (event) => listener(event.detail) : listener;
|
|
663
|
+
target.addEventListener(name, adapter);
|
|
636
664
|
return () => {
|
|
637
|
-
target.removeEventListener(name,
|
|
665
|
+
target.removeEventListener(name, adapter);
|
|
638
666
|
};
|
|
639
667
|
}
|
|
640
668
|
//#endregion
|
|
@@ -669,4 +697,4 @@ function useListener(target, name, listener) {
|
|
|
669
697
|
}, [target, name]);
|
|
670
698
|
}
|
|
671
699
|
//#endregion
|
|
672
|
-
export { SigmaType, action, batch, computed, effect, freeze, immerable, isSigmaState, listen, query, replaceState, setAutoFreeze, snapshot, untracked, useListener, useSigma };
|
|
700
|
+
export { SigmaTarget, SigmaType, action, batch, computed, effect, freeze, immerable, isSigmaState, listen, query, replaceState, setAutoFreeze, snapshot, untracked, useListener, useSigma };
|
package/docs/context.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Overview
|
|
2
2
|
|
|
3
|
-
`preact-sigma` builds reusable state models from one definition. A configured `SigmaType` owns top-level state, derived reads, writes, setup handlers, and typed events. Each top-level state property is exposed as a reactive public property backed by its own Preact signal, while actions use Immer-style mutation semantics to publish committed state.
|
|
3
|
+
`preact-sigma` builds reusable state models from one definition. A configured `SigmaType` owns top-level state, derived reads, writes, setup handlers, and typed events. Each top-level state property is exposed as a reactive public property backed by its own Preact signal, while actions use Immer-style mutation semantics to publish committed state. For event-only flows, `SigmaTarget` provides a standalone typed event hub with no managed state.
|
|
4
4
|
|
|
5
5
|
# When to Use
|
|
6
6
|
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
|
|
22
22
|
- Sigma type: the builder returned by `new SigmaType<TState, TEvents>()`. After configuration, it is also the constructor for instances.
|
|
23
23
|
- Sigma state: an instance created from a configured sigma type.
|
|
24
|
+
- Sigma target: a standalone typed event hub created with `new SigmaTarget<TEvents>()` when you need typed events without managed state.
|
|
24
25
|
- State property: a top-level key from `TState`. Each one becomes a readonly reactive public property and gets its own signal.
|
|
25
26
|
- Computed: an argument-free derived getter declared with `.computed(...)`.
|
|
26
27
|
- Query: a reactive read that accepts arguments, declared with `.queries(...)` or built locally with `query(fn)`.
|
|
@@ -51,6 +52,7 @@
|
|
|
51
52
|
- Own timers, listeners, subscriptions, or nested setup: `.setup(...)`
|
|
52
53
|
- Use a sigma state inside a component: `useSigma(...)`
|
|
53
54
|
- Subscribe to sigma or DOM events in a component: `useListener(...)`
|
|
55
|
+
- Create a standalone typed event hub with no managed state: `new SigmaTarget<TEvents>()`, `hub.emit(...)`, and `hub.on(...)`
|
|
54
56
|
- Subscribe outside components: `.on(...)` or `listen(...)`
|
|
55
57
|
- Read or restore committed top-level state: `snapshot(...)` and `replaceState(...)`
|
|
56
58
|
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { listen, SigmaTarget } from "preact-sigma";
|
|
2
|
+
|
|
3
|
+
const notifications = new SigmaTarget<{
|
|
4
|
+
saved: {
|
|
5
|
+
id: string;
|
|
6
|
+
title: string;
|
|
7
|
+
};
|
|
8
|
+
reset: void;
|
|
9
|
+
}>();
|
|
10
|
+
|
|
11
|
+
const stopSaved = notifications.on("saved", ({ id, title }) => {
|
|
12
|
+
console.log(`Saved ${id}: ${title}`);
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
const stopReset = listen(notifications, "reset", () => {
|
|
16
|
+
console.log("Reset");
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
notifications.emit("saved", {
|
|
20
|
+
id: "note-1",
|
|
21
|
+
title: "Draft post",
|
|
22
|
+
});
|
|
23
|
+
notifications.emit("reset");
|
|
24
|
+
|
|
25
|
+
stopSaved();
|
|
26
|
+
stopReset();
|