cereb 0.12.0 → 1.0.1
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 +5 -3
- package/dist/browser/multi-pointer/multi-pointer-signal.d.ts +3 -4
- package/dist/browser/multi-pointer/multi-pointer-signal.d.ts.map +1 -1
- package/dist/browser/single-pointer/recognizer-from-mouse.d.ts.map +1 -1
- package/dist/browser/single-pointer/recognizer-from-pointer.d.ts.map +1 -1
- package/dist/browser/single-pointer/recognizer-from-touch.d.ts.map +1 -1
- package/dist/browser/single-pointer/single-pointer-signal.d.ts +3 -4
- package/dist/browser/single-pointer/single-pointer-signal.d.ts.map +1 -1
- package/dist/frp/behavior.d.ts +69 -0
- package/dist/frp/behavior.d.ts.map +1 -0
- package/dist/frp/combinators.d.ts +41 -0
- package/dist/frp/combinators.d.ts.map +1 -0
- package/dist/frp/conversions.d.ts +97 -0
- package/dist/frp/conversions.d.ts.map +1 -0
- package/dist/frp/event.d.ts +15 -0
- package/dist/frp/event.d.ts.map +1 -0
- package/dist/frp/index.d.ts +5 -0
- package/dist/frp/index.d.ts.map +1 -0
- package/dist/frp.cjs +2 -0
- package/dist/frp.cjs.map +1 -0
- package/dist/frp.d.ts +21 -0
- package/dist/frp.d.ts.map +1 -0
- package/dist/frp.js +473 -0
- package/dist/frp.js.map +1 -0
- package/dist/geometry/creators.d.ts +8 -0
- package/dist/geometry/creators.d.ts.map +1 -0
- package/dist/geometry/index.d.ts +4 -0
- package/dist/geometry/index.d.ts.map +1 -0
- package/dist/geometry/operations.d.ts +14 -0
- package/dist/geometry/operations.d.ts.map +1 -0
- package/dist/geometry/types.d.ts +10 -0
- package/dist/geometry/types.d.ts.map +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +291 -205
- package/dist/index.js.map +1 -1
- package/dist/operators/offset.d.ts +3 -4
- package/dist/operators/offset.d.ts.map +1 -1
- package/dist/operators.cjs +1 -1
- package/dist/operators.cjs.map +1 -1
- package/dist/operators.js +22 -22
- package/dist/operators.js.map +1 -1
- package/dist/recognizer-3x1IWMaJ.cjs +2 -0
- package/dist/recognizer-3x1IWMaJ.cjs.map +1 -0
- package/dist/recognizer-wJJrCf-d.js +38 -0
- package/dist/recognizer-wJJrCf-d.js.map +1 -0
- package/dist/signal-BxXaEoCj.cjs +2 -0
- package/dist/signal-BxXaEoCj.cjs.map +1 -0
- package/dist/signal-DyM698s7.js +20 -0
- package/dist/signal-DyM698s7.js.map +1 -0
- package/dist/single-pointer/mouse.cjs +1 -1
- package/dist/single-pointer/mouse.cjs.map +1 -1
- package/dist/single-pointer/mouse.js +19 -19
- package/dist/single-pointer/mouse.js.map +1 -1
- package/dist/single-pointer/pointer.cjs +1 -1
- package/dist/single-pointer/pointer.cjs.map +1 -1
- package/dist/single-pointer/pointer.js +16 -16
- package/dist/single-pointer/pointer.js.map +1 -1
- package/dist/single-pointer/touch.cjs +1 -1
- package/dist/single-pointer/touch.cjs.map +1 -1
- package/dist/single-pointer/touch.js +13 -13
- package/dist/single-pointer/touch.js.map +1 -1
- package/package.json +9 -14
- package/dist/recognizer-BzvWMkxq.js +0 -56
- package/dist/recognizer-BzvWMkxq.js.map +0 -1
- package/dist/recognizer-D3UwuOb3.cjs +0 -2
- package/dist/recognizer-D3UwuOb3.cjs.map +0 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# [Cereb](https://cereb.dev)
|
|
2
2
|
|
|
3
|
-
**User input handling and orchestration**
|
|
3
|
+
**User input handling and orchestration** library,
|
|
4
4
|
From low-level events (keyboard, wheel, pointer, ...) to high-level gestures (pan, pinch, ...)
|
|
5
5
|
|
|
6
6
|
```bash
|
|
@@ -21,7 +21,8 @@ singlePointer(canvas)
|
|
|
21
21
|
// Listen to stream events
|
|
22
22
|
.on((signal) => {
|
|
23
23
|
// Receive signals from the stream
|
|
24
|
-
const { phase,
|
|
24
|
+
const { phase, cursor } = signal.value;
|
|
25
|
+
const [x, y] = cursor;
|
|
25
26
|
switch (phase){
|
|
26
27
|
case "move":
|
|
27
28
|
element.style.transform = `translate(${x}px, ${y}px)`;
|
|
@@ -40,6 +41,7 @@ For advanced gestures like pan or pinch, install dedicated packages that build o
|
|
|
40
41
|
|---------|-------------|
|
|
41
42
|
| [@cereb/pan](https://www.npmjs.com/package/@cereb/pan) | Pan/drag gestures with velocity and direction tracking |
|
|
42
43
|
| [@cereb/pinch](https://www.npmjs.com/package/@cereb/pinch) | Pinch-to-zoom with distance and scale calculations |
|
|
44
|
+
| [@cereb/tap](https://www.npmjs.com/package/@cereb/tap) | Tap gesture recognition |
|
|
43
45
|
|
|
44
46
|
### Pinch example
|
|
45
47
|
|
|
@@ -91,7 +93,7 @@ Transform and compose streams with operators like `filter`, `map`, `merge`, `thr
|
|
|
91
93
|
|
|
92
94
|
## The Problems Cereb Solves
|
|
93
95
|
|
|
94
|
-
- **
|
|
96
|
+
- **No Abstraction for Event Flow** — DOM events lack structure for state, dependencies, and composition
|
|
95
97
|
- **Lightweight Bundle** — ~77% smaller than Hammer.js (1.73 KB gzipped for pan gesture)
|
|
96
98
|
- **Resource Efficiency** — Event listener reuse, single-responsibility operators
|
|
97
99
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Signal } from '../../core/signal.js';
|
|
2
|
+
import { Point } from '../../geometry/types.js';
|
|
2
3
|
import { SinglePointerButton, SinglePointerPhase, SinglePointerType } from '../single-pointer/types.js';
|
|
3
4
|
export interface MultiPointerSignal extends Signal<"multi-pointer", MultiPointer> {
|
|
4
5
|
}
|
|
@@ -28,10 +29,8 @@ export type MultiPointerPhase = "idle" | "active" | "ended";
|
|
|
28
29
|
export interface PointerInfo {
|
|
29
30
|
id: string;
|
|
30
31
|
phase: SinglePointerPhase;
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
pageX: number;
|
|
34
|
-
pageY: number;
|
|
32
|
+
cursor: Point;
|
|
33
|
+
pageCursor: Point;
|
|
35
34
|
pointerType: SinglePointerType;
|
|
36
35
|
button: SinglePointerButton;
|
|
37
36
|
/** 0.0 ~ 1.0, default 0.5 if unsupported */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"multi-pointer-signal.d.ts","sourceRoot":"","sources":["../../../src/browser/multi-pointer/multi-pointer-signal.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,MAAM,EAAE,MAAM,sBAAsB,CAAC;AACjE,OAAO,KAAK,EACV,mBAAmB,EACnB,kBAAkB,EAClB,iBAAiB,EAClB,MAAM,4BAA4B,CAAC;AAEpC,MAAM,WAAW,kBAAmB,SAAQ,MAAM,CAAC,eAAe,EAAE,YAAY,CAAC;CAAG;AAEpF,eAAO,MAAM,yBAAyB,EAAG,eAAwB,CAAC;AAElE;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC3B,kFAAkF;IAClF,KAAK,EAAE,iBAAiB,CAAC;IACzB,yCAAyC;IACzC,QAAQ,EAAE,SAAS,WAAW,EAAE,CAAC;IACjC,sCAAsC;IACtC,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;;;;GAKG;AACH,MAAM,MAAM,iBAAiB,GAAG,MAAM,GAAG,QAAQ,GAAG,OAAO,CAAC;AAE5D;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,kBAAkB,CAAC;IAC1B,
|
|
1
|
+
{"version":3,"file":"multi-pointer-signal.d.ts","sourceRoot":"","sources":["../../../src/browser/multi-pointer/multi-pointer-signal.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,MAAM,EAAE,MAAM,sBAAsB,CAAC;AACjE,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,yBAAyB,CAAC;AACrD,OAAO,KAAK,EACV,mBAAmB,EACnB,kBAAkB,EAClB,iBAAiB,EAClB,MAAM,4BAA4B,CAAC;AAEpC,MAAM,WAAW,kBAAmB,SAAQ,MAAM,CAAC,eAAe,EAAE,YAAY,CAAC;CAAG;AAEpF,eAAO,MAAM,yBAAyB,EAAG,eAAwB,CAAC;AAElE;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC3B,kFAAkF;IAClF,KAAK,EAAE,iBAAiB,CAAC;IACzB,yCAAyC;IACzC,QAAQ,EAAE,SAAS,WAAW,EAAE,CAAC;IACjC,sCAAsC;IACtC,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;;;;GAKG;AACH,MAAM,MAAM,iBAAiB,GAAG,MAAM,GAAG,QAAQ,GAAG,OAAO,CAAC;AAE5D;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,kBAAkB,CAAC;IAC1B,MAAM,EAAE,KAAK,CAAC;IACd,UAAU,EAAE,KAAK,CAAC;IAClB,WAAW,EAAE,iBAAiB,CAAC;IAC/B,MAAM,EAAE,mBAAmB,CAAC;IAC5B,4CAA4C;IAC5C,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,wBAAgB,wBAAwB,CAAC,YAAY,EAAE,YAAY,GAAG,kBAAkB,CAEvF;AAED,wBAAgB,wBAAwB,IAAI,WAAW,CAUtD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"recognizer-from-mouse.d.ts","sourceRoot":"","sources":["../../../src/browser/single-pointer/recognizer-from-mouse.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAGrD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kCAAkC,CAAC;AACvE,OAAO,EAAiC,KAAK,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAC9F,OAAO,KAAK,EAAiB,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACrF,OAAO,EAEL,KAAK,oBAAoB,EAG1B,MAAM,YAAY,CAAC;AAEpB,wBAAgB,qBAAqB,CACnC,OAAO,GAAE,oBAAyB,GACjC,uBAAuB,CAAC,cAAc,CAAC,UAAU,CAAC,CAAC,
|
|
1
|
+
{"version":3,"file":"recognizer-from-mouse.d.ts","sourceRoot":"","sources":["../../../src/browser/single-pointer/recognizer-from-mouse.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAGrD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kCAAkC,CAAC;AACvE,OAAO,EAAiC,KAAK,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAC9F,OAAO,KAAK,EAAiB,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACrF,OAAO,EAEL,KAAK,oBAAoB,EAG1B,MAAM,YAAY,CAAC;AAEpB,wBAAgB,qBAAqB,CACnC,OAAO,GAAE,oBAAyB,GACjC,uBAAuB,CAAC,cAAc,CAAC,UAAU,CAAC,CAAC,CAkCrD;AAED,wBAAgB,sBAAsB,CACpC,OAAO,GAAE,oBAAyB,GACjC,QAAQ,CAAC,cAAc,CAAC,UAAU,CAAC,EAAE,mBAAmB,CAAC,CAyB3D"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"recognizer-from-pointer.d.ts","sourceRoot":"","sources":["../../../src/browser/single-pointer/recognizer-from-pointer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAGrD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kCAAkC,CAAC;AACvE,OAAO,EAAiC,KAAK,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAC9F,OAAO,KAAK,EAAiB,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACrF,OAAO,EAEL,KAAK,oBAAoB,EAI1B,MAAM,YAAY,CAAC;AAEpB,wBAAgB,uBAAuB,CACrC,OAAO,GAAE,oBAAyB,GACjC,uBAAuB,CAAC,cAAc,CAAC,YAAY,CAAC,CAAC,
|
|
1
|
+
{"version":3,"file":"recognizer-from-pointer.d.ts","sourceRoot":"","sources":["../../../src/browser/single-pointer/recognizer-from-pointer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAGrD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kCAAkC,CAAC;AACvE,OAAO,EAAiC,KAAK,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAC9F,OAAO,KAAK,EAAiB,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACrF,OAAO,EAEL,KAAK,oBAAoB,EAI1B,MAAM,YAAY,CAAC;AAEpB,wBAAgB,uBAAuB,CACrC,OAAO,GAAE,oBAAyB,GACjC,uBAAuB,CAAC,cAAc,CAAC,YAAY,CAAC,CAAC,CA2CvD;AAED,wBAAgB,wBAAwB,CACtC,OAAO,GAAE,oBAAyB,GACjC,QAAQ,CAAC,cAAc,CAAC,YAAY,CAAC,EAAE,mBAAmB,CAAC,CAyB7D"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"recognizer-from-touch.d.ts","sourceRoot":"","sources":["../../../src/browser/single-pointer/recognizer-from-touch.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAGrD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kCAAkC,CAAC;AACvE,OAAO,EAAiC,KAAK,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAC9F,OAAO,KAAK,EAAiB,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACrF,OAAO,KAAK,EAAE,oBAAoB,EAAsB,MAAM,YAAY,CAAC;AAE3E,wBAAgB,qBAAqB,CACnC,OAAO,GAAE,oBAAyB,GACjC,uBAAuB,CAAC,cAAc,CAAC,UAAU,CAAC,CAAC,
|
|
1
|
+
{"version":3,"file":"recognizer-from-touch.d.ts","sourceRoot":"","sources":["../../../src/browser/single-pointer/recognizer-from-touch.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAGrD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kCAAkC,CAAC;AACvE,OAAO,EAAiC,KAAK,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAC9F,OAAO,KAAK,EAAiB,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACrF,OAAO,KAAK,EAAE,oBAAoB,EAAsB,MAAM,YAAY,CAAC;AAE3E,wBAAgB,qBAAqB,CACnC,OAAO,GAAE,oBAAyB,GACjC,uBAAuB,CAAC,cAAc,CAAC,UAAU,CAAC,CAAC,CAkCrD;AAED,wBAAgB,sBAAsB,CACpC,OAAO,GAAE,oBAAyB,GACjC,QAAQ,CAAC,cAAc,CAAC,UAAU,CAAC,EAAE,mBAAmB,CAAC,CAyB3D"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Signal } from '../../core/signal.js';
|
|
2
|
+
import { Point } from '../../geometry/types.js';
|
|
2
3
|
import { SinglePointerButton, SinglePointerPhase, SinglePointerType } from './types.js';
|
|
3
4
|
export interface SinglePointerSignal extends Signal<"single-pointer", SinglePointer> {
|
|
4
5
|
}
|
|
@@ -9,10 +10,8 @@ export declare const SINGLE_POINTER_SIGNAL_KIND: "single-pointer";
|
|
|
9
10
|
*/
|
|
10
11
|
export interface SinglePointer {
|
|
11
12
|
phase: SinglePointerPhase;
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
pageX: number;
|
|
15
|
-
pageY: number;
|
|
13
|
+
cursor: Point;
|
|
14
|
+
pageCursor: Point;
|
|
16
15
|
pointerType: SinglePointerType;
|
|
17
16
|
button: SinglePointerButton;
|
|
18
17
|
/** 0.0 ~ 1.0, default 0.5 if unsupported */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"single-pointer-signal.d.ts","sourceRoot":"","sources":["../../../src/browser/single-pointer/single-pointer-signal.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,MAAM,EAAE,MAAM,sBAAsB,CAAC;AACjE,OAAO,KAAK,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAE7F,MAAM,WAAW,mBAAoB,SAAQ,MAAM,CAAC,gBAAgB,EAAE,aAAa,CAAC;CAAG;AAEvF,eAAO,MAAM,0BAA0B,EAAG,gBAAyB,CAAC;AAEpE;;;GAGG;AACH,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,kBAAkB,CAAC;IAC1B,
|
|
1
|
+
{"version":3,"file":"single-pointer-signal.d.ts","sourceRoot":"","sources":["../../../src/browser/single-pointer/single-pointer-signal.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,MAAM,EAAE,MAAM,sBAAsB,CAAC;AACjE,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,yBAAyB,CAAC;AACrD,OAAO,KAAK,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAE7F,MAAM,WAAW,mBAAoB,SAAQ,MAAM,CAAC,gBAAgB,EAAE,aAAa,CAAC;CAAG;AAEvF,eAAO,MAAM,0BAA0B,EAAG,gBAAyB,CAAC;AAEpE;;;GAGG;AACH,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,kBAAkB,CAAC;IAC1B,MAAM,EAAE,KAAK,CAAC;IACd,UAAU,EAAE,KAAK,CAAC;IAClB,WAAW,EAAE,iBAAiB,CAAC;IAC/B,MAAM,EAAE,mBAAmB,CAAC;IAC5B,4CAA4C;IAC5C,QAAQ,EAAE,MAAM,CAAC;IACjB,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,aAAa,GAAG,mBAAmB,CAErF;AAED,wBAAgB,gCAAgC,IAAI,mBAAmB,CAUtE"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { Signal, Stream } from '../core/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* Behavior represents a value that changes continuously over time.
|
|
4
|
+
* Unlike Stream (Event), Behavior always has a current value that can be sampled.
|
|
5
|
+
*
|
|
6
|
+
* Key concepts:
|
|
7
|
+
* - sample(): Get the current value at any point in time
|
|
8
|
+
* - map(): Transform the value (Functor)
|
|
9
|
+
* - ap(): Apply a function behavior to this behavior (Applicative)
|
|
10
|
+
* - onChange(): Subscribe to value changes (Push notification)
|
|
11
|
+
* - dispose(): Clean up resources and subscriptions
|
|
12
|
+
*
|
|
13
|
+
* @typeParam A - The type of the value
|
|
14
|
+
*/
|
|
15
|
+
export interface Behavior<A> {
|
|
16
|
+
/** Sample the current value */
|
|
17
|
+
sample(): A;
|
|
18
|
+
/** Transform the value (Functor map) */
|
|
19
|
+
map<B>(f: (a: A) => B): Behavior<B>;
|
|
20
|
+
/**
|
|
21
|
+
* Apply a function from another Behavior to this value (Applicative apply)
|
|
22
|
+
* Note: The function behavior is the receiver, value behavior is the argument
|
|
23
|
+
*/
|
|
24
|
+
ap<B>(this: Behavior<(b: B) => A>, bb: Behavior<B>): Behavior<A>;
|
|
25
|
+
/** Subscribe to value changes. Returns an unsubscribe function. */
|
|
26
|
+
onChange(callback: (a: A) => void): () => void;
|
|
27
|
+
/** Dispose the behavior and clean up all resources */
|
|
28
|
+
dispose(): void;
|
|
29
|
+
/** Returns true if the behavior has been disposed */
|
|
30
|
+
readonly isDisposed: boolean;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Creates a constant Behavior that never changes.
|
|
34
|
+
* The value is fixed at creation time.
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* const always42 = constant(42);
|
|
38
|
+
* always42.sample(); // 42
|
|
39
|
+
*/
|
|
40
|
+
export declare function constant<A>(value: A): Behavior<A>;
|
|
41
|
+
/**
|
|
42
|
+
* Creates a Behavior from an event stream with an initial value.
|
|
43
|
+
* The behavior holds the latest value from the stream.
|
|
44
|
+
*
|
|
45
|
+
* @param initial - The initial value before any events
|
|
46
|
+
* @param event - The event stream to listen to
|
|
47
|
+
* @param selector - Function to extract the value from each signal
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* const position = stepper(
|
|
51
|
+
* { x: 0, y: 0 },
|
|
52
|
+
* pointerStream,
|
|
53
|
+
* (signal) => signal.value.position
|
|
54
|
+
* );
|
|
55
|
+
*/
|
|
56
|
+
export declare function stepper<A, S extends Signal>(initial: A, event: Stream<S>, selector: (signal: S) => A): Behavior<A>;
|
|
57
|
+
/**
|
|
58
|
+
* Creates a Behavior that represents the current time.
|
|
59
|
+
* Each sample() call returns the current timestamp (performance.now()).
|
|
60
|
+
*
|
|
61
|
+
* Note: onChange() is not meaningful for time as it always changes.
|
|
62
|
+
* Use animationFrame() from conversions if you need time-based events.
|
|
63
|
+
*
|
|
64
|
+
* @example
|
|
65
|
+
* const t = time();
|
|
66
|
+
* const now = t.sample(); // current timestamp
|
|
67
|
+
*/
|
|
68
|
+
export declare function time(): Behavior<number>;
|
|
69
|
+
//# sourceMappingURL=behavior.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"behavior.d.ts","sourceRoot":"","sources":["../../src/frp/behavior.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAEvD;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,QAAQ,CAAC,CAAC;IACzB,+BAA+B;IAC/B,MAAM,IAAI,CAAC,CAAC;IAEZ,wCAAwC;IACxC,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;IAEpC;;;OAGG;IACH,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,EAAE,QAAQ,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;IAEjE,mEAAmE;IACnE,QAAQ,CAAC,QAAQ,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;IAE/C,sDAAsD;IACtD,OAAO,IAAI,IAAI,CAAC;IAEhB,qDAAqD;IACrD,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;CAC9B;AAuDD;;;;;;;GAOG;AACH,wBAAgB,QAAQ,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAgCjD;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,OAAO,CAAC,CAAC,EAAE,CAAC,SAAS,MAAM,EACzC,OAAO,EAAE,CAAC,EACV,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,EAChB,QAAQ,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,GACzB,QAAQ,CAAC,CAAC,CAAC,CAqCb;AA+ED;;;;;;;;;;GAUG;AACH,wBAAgB,IAAI,IAAI,QAAQ,CAAC,MAAM,CAAC,CAiDvC"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { Behavior } from './behavior.js';
|
|
2
|
+
/**
|
|
3
|
+
* Combines multiple Behaviors into one using a combining function.
|
|
4
|
+
* The result updates whenever any source behavior changes.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* const transform = combine(
|
|
8
|
+
* positionBehavior,
|
|
9
|
+
* scaleBehavior,
|
|
10
|
+
* rotationBehavior,
|
|
11
|
+
* (pos, scale, rot) => ({ pos, scale, rot })
|
|
12
|
+
* );
|
|
13
|
+
*/
|
|
14
|
+
export declare function combine<A, B, R>(a: Behavior<A>, b: Behavior<B>, f: (a: A, b: B) => R): Behavior<R>;
|
|
15
|
+
export declare function combine<A, B, C, R>(a: Behavior<A>, b: Behavior<B>, c: Behavior<C>, f: (a: A, b: B, c: C) => R): Behavior<R>;
|
|
16
|
+
export declare function combine<A, B, C, D, R>(a: Behavior<A>, b: Behavior<B>, c: Behavior<C>, d: Behavior<D>, f: (a: A, b: B, c: C, d: D) => R): Behavior<R>;
|
|
17
|
+
export declare function combine<A, B, C, D, E, R>(a: Behavior<A>, b: Behavior<B>, c: Behavior<C>, d: Behavior<D>, e: Behavior<E>, f: (a: A, b: B, c: C, d: D, e: E) => R): Behavior<R>;
|
|
18
|
+
/**
|
|
19
|
+
* Selects between two Behaviors based on a boolean condition Behavior.
|
|
20
|
+
* When condition is true, samples from ifTrue; otherwise from ifFalse.
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* const displayValue = switcher(
|
|
24
|
+
* isEditMode,
|
|
25
|
+
* editableValue,
|
|
26
|
+
* readonlyValue
|
|
27
|
+
* );
|
|
28
|
+
*/
|
|
29
|
+
export declare function switcher<A>(condition: Behavior<boolean>, ifTrue: Behavior<A>, ifFalse: Behavior<A>): Behavior<A>;
|
|
30
|
+
/**
|
|
31
|
+
* Lifts a pure function to work with Behaviors.
|
|
32
|
+
* Equivalent to combining behaviors and applying a function.
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* const add = (a: number, b: number) => a + b;
|
|
36
|
+
* const sumBehavior = lift(add)(behaviorA, behaviorB);
|
|
37
|
+
*/
|
|
38
|
+
export declare function lift<A, R>(f: (a: A) => R): (ba: Behavior<A>) => Behavior<R>;
|
|
39
|
+
export declare function lift<A, B, R>(f: (a: A, b: B) => R): (ba: Behavior<A>, bb: Behavior<B>) => Behavior<R>;
|
|
40
|
+
export declare function lift<A, B, C, R>(f: (a: A, b: B, c: C) => R): (ba: Behavior<A>, bb: Behavior<B>, bc: Behavior<C>) => Behavior<R>;
|
|
41
|
+
//# sourceMappingURL=combinators.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"combinators.d.ts","sourceRoot":"","sources":["../../src/frp/combinators.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { Signal, Stream } from '../core/index.js';
|
|
2
|
+
import { Behavior } from './behavior.js';
|
|
3
|
+
/**
|
|
4
|
+
* Signal type for behavior change events
|
|
5
|
+
*/
|
|
6
|
+
export type BehaviorChangeSignal<A> = Signal<"behavior-change", A>;
|
|
7
|
+
/**
|
|
8
|
+
* Signal type for sampled values
|
|
9
|
+
*/
|
|
10
|
+
export type SampledSignal<A> = Signal<"sampled", A>;
|
|
11
|
+
/**
|
|
12
|
+
* Signal type for animation frame samples
|
|
13
|
+
*/
|
|
14
|
+
export type FrameSignal<A> = Signal<"frame", {
|
|
15
|
+
value: A;
|
|
16
|
+
timestamp: number;
|
|
17
|
+
}>;
|
|
18
|
+
/**
|
|
19
|
+
* Converts a Behavior to an Event (Stream) that fires when the value changes.
|
|
20
|
+
* This is the Behavior → Event conversion.
|
|
21
|
+
*
|
|
22
|
+
* @param behavior - The behavior to observe
|
|
23
|
+
* @returns A stream that emits signals whenever the behavior's value changes
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* const positionChanges = changes(positionBehavior);
|
|
27
|
+
* positionChanges.on(signal => {
|
|
28
|
+
* console.log('Position changed to:', signal.value);
|
|
29
|
+
* });
|
|
30
|
+
*/
|
|
31
|
+
export declare function changes<A>(behavior: Behavior<A>): Stream<BehaviorChangeSignal<A>>;
|
|
32
|
+
/**
|
|
33
|
+
* Samples a Behavior at regular intervals.
|
|
34
|
+
*
|
|
35
|
+
* @param behavior - The behavior to sample
|
|
36
|
+
* @param intervalMs - The sampling interval in milliseconds
|
|
37
|
+
* @returns A stream that emits the sampled value at each interval
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* const positionSamples = sample(positionBehavior, 16); // ~60fps
|
|
41
|
+
* positionSamples.on(signal => {
|
|
42
|
+
* updateDisplay(signal.value);
|
|
43
|
+
* });
|
|
44
|
+
*/
|
|
45
|
+
export declare function sample<A>(behavior: Behavior<A>, intervalMs: number): Stream<SampledSignal<A>>;
|
|
46
|
+
/**
|
|
47
|
+
* Samples a Behavior whenever another event occurs.
|
|
48
|
+
* Useful for getting the current state at specific moments.
|
|
49
|
+
*
|
|
50
|
+
* @param behavior - The behavior to sample
|
|
51
|
+
* @param trigger - The trigger event stream
|
|
52
|
+
* @returns A stream that emits the sampled value along with the trigger signal
|
|
53
|
+
*
|
|
54
|
+
* @example
|
|
55
|
+
* const positionOnClick = sampleOn(positionBehavior, clickStream);
|
|
56
|
+
* positionOnClick.on(signal => {
|
|
57
|
+
* console.log('Position at click:', signal.value.value);
|
|
58
|
+
* console.log('Click event:', signal.value.trigger);
|
|
59
|
+
* });
|
|
60
|
+
*/
|
|
61
|
+
export declare function sampleOn<A, S extends Signal>(behavior: Behavior<A>, trigger: Stream<S>): Stream<Signal<"sampled-on", {
|
|
62
|
+
value: A;
|
|
63
|
+
trigger: S;
|
|
64
|
+
}>>;
|
|
65
|
+
/**
|
|
66
|
+
* Samples a Behavior on every animation frame using requestAnimationFrame.
|
|
67
|
+
* Ideal for rendering loops and smooth animations.
|
|
68
|
+
*
|
|
69
|
+
* @param behavior - The behavior to sample
|
|
70
|
+
* @returns A stream that emits on each animation frame with the sampled value and timestamp
|
|
71
|
+
*
|
|
72
|
+
* @example
|
|
73
|
+
* const frameStream = animationFrame(transformBehavior);
|
|
74
|
+
* frameStream.on(({ value }) => {
|
|
75
|
+
* element.style.transform = `translate(${value.x}px, ${value.y}px)`;
|
|
76
|
+
* });
|
|
77
|
+
*/
|
|
78
|
+
export declare function animationFrame<A>(behavior: Behavior<A>): Stream<FrameSignal<A>>;
|
|
79
|
+
/**
|
|
80
|
+
* Creates a Behavior that tracks elapsed time since creation.
|
|
81
|
+
* The elapsed time is updated on each animation frame.
|
|
82
|
+
*
|
|
83
|
+
* Note: This returns both a Behavior and a dispose function.
|
|
84
|
+
* Call dispose() when you no longer need the elapsed time tracking.
|
|
85
|
+
*
|
|
86
|
+
* @returns Object containing the elapsed behavior and dispose function
|
|
87
|
+
*
|
|
88
|
+
* @example
|
|
89
|
+
* const { elapsed, dispose } = elapsedTime();
|
|
90
|
+
* // Use elapsed.sample() to get time since creation
|
|
91
|
+
* // Call dispose() when done
|
|
92
|
+
*/
|
|
93
|
+
export declare function elapsedTime(): {
|
|
94
|
+
elapsed: Behavior<number>;
|
|
95
|
+
dispose: () => void;
|
|
96
|
+
};
|
|
97
|
+
//# sourceMappingURL=conversions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"conversions.d.ts","sourceRoot":"","sources":["../../src/frp/conversions.ts"],"names":[],"mappings":"AAAA,OAAO,EAA8B,KAAK,MAAM,EAAE,KAAK,MAAM,EAAE,MAAM,kBAAkB,CAAC;AACxF,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAE9C;;GAEG;AACH,MAAM,MAAM,oBAAoB,CAAC,CAAC,IAAI,MAAM,CAAC,iBAAiB,EAAE,CAAC,CAAC,CAAC;AAEnE;;GAEG;AACH,MAAM,MAAM,aAAa,CAAC,CAAC,IAAI,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC;AAEpD;;GAEG;AACH,MAAM,MAAM,WAAW,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,EAAE;IAAE,KAAK,EAAE,CAAC,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAE9E;;;;;;;;;;;;GAYG;AACH,wBAAgB,OAAO,CAAC,CAAC,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,oBAAoB,CAAC,CAAC,CAAC,CAAC,CAUjF;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,MAAM,CAAC,CAAC,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAY7F;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,QAAQ,CAAC,CAAC,EAAE,CAAC,SAAS,MAAM,EAC1C,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC,EACrB,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC,GACjB,MAAM,CAAC,MAAM,CAAC,YAAY,EAAE;IAAE,KAAK,EAAE,CAAC,CAAC;IAAC,OAAO,EAAE,CAAC,CAAA;CAAE,CAAC,CAAC,CAexD;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CA2B/E;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,WAAW,IAAI;IAAE,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IAAC,OAAO,EAAE,MAAM,IAAI,CAAA;CAAE,CAmDhF"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Signal, Stream } from '../core/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* Event represents discrete occurrences over time.
|
|
4
|
+
* This is a semantic alias for Stream<Signal> to align with FRP terminology.
|
|
5
|
+
*
|
|
6
|
+
* In FRP theory:
|
|
7
|
+
* - Event = discrete occurrences (clicks, key presses, gesture signals)
|
|
8
|
+
* - Behavior = continuous values over time (position, scale)
|
|
9
|
+
*
|
|
10
|
+
* Event uses all existing Stream operations: pipe(), filter(), map(), etc.
|
|
11
|
+
*
|
|
12
|
+
* @typeParam S - The Signal type for this event stream
|
|
13
|
+
*/
|
|
14
|
+
export type Event<S extends Signal> = Stream<S>;
|
|
15
|
+
//# sourceMappingURL=event.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event.d.ts","sourceRoot":"","sources":["../../src/frp/event.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAEvD;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,KAAK,CAAC,CAAC,SAAS,MAAM,IAAI,MAAM,CAAC,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { type Behavior, constant, stepper, time } from './behavior.js';
|
|
2
|
+
export { combine, lift, switcher } from './combinators.js';
|
|
3
|
+
export { animationFrame, type BehaviorChangeSignal, changes, elapsedTime, type FrameSignal, type SampledSignal, sample, sampleOn, } from './conversions.js';
|
|
4
|
+
export type { Event } from './event.js';
|
|
5
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/frp/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAEvE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE3D,OAAO,EACL,cAAc,EACd,KAAK,oBAAoB,EACzB,OAAO,EACP,WAAW,EACX,KAAK,WAAW,EAChB,KAAK,aAAa,EAClB,MAAM,EACN,QAAQ,GACT,MAAM,kBAAkB,CAAC;AAE1B,YAAY,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC"}
|
package/dist/frp.cjs
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const m=require("./stream-BvdJvQie.cjs"),h=require("./signal-BxXaEoCj.cjs");function w(r,t){const e=new Set;let n=!1;return{behavior:{sample:()=>{if(n)throw new Error("Cannot sample a disposed Behavior");return r()},onChange:o=>n?()=>{}:(e.add(o),()=>e.delete(o)),dispose:()=>{n||(n=!0,e.clear(),t?.())},get isDisposed(){return n}},listeners:e,notifyListeners:()=>{if(n)return;const o=r();for(const a of e)a(o)},isDisposed:()=>n}}function g(r){let t=!1;return{sample:()=>{if(t)throw new Error("Cannot sample a disposed Behavior");return r},map:n=>{if(t)throw new Error("Cannot map a disposed Behavior");return g(n(r))},ap:function(n){if(t)throw new Error("Cannot apply a disposed Behavior");return g(this.sample()(n.sample()))},onChange:()=>()=>{},dispose:()=>{t=!0},get isDisposed(){return t}}}function y(r,t,e){let n=r,s=null;const{behavior:o,notifyListeners:a,isDisposed:p}=w(()=>n,()=>{s?.(),s=null});s=t.on(i=>{if(p())return;const l=e(i);Object.is(l,n)||(n=l,a())});const u={sample:o.sample,onChange:o.onChange,dispose:o.dispose,get isDisposed(){return o.isDisposed},map:i=>v(u,i),ap:function(i){return c(this,i)}};return u}function v(r,t){const{behavior:e,notifyListeners:n,isDisposed:s}=w(()=>t(r.sample()),()=>{o?.()}),o=r.onChange(()=>{s()||n()}),a={sample:e.sample,onChange:e.onChange,dispose:e.dispose,get isDisposed(){return e.isDisposed},map:p=>v(a,p),ap:function(p){return c(this,p)}};return a}function c(r,t){const{behavior:e,notifyListeners:n,isDisposed:s}=w(()=>r.sample()(t.sample()),()=>{o?.(),a?.()}),o=r.onChange(()=>{s()||n()}),a=t.onChange(()=>{s()||n()}),p={sample:e.sample,onChange:e.onChange,dispose:e.dispose,get isDisposed(){return e.isDisposed},map:u=>v(p,u),ap:function(u){return c(this,u)}};return p}function F(){let r=!1;const t={sample:()=>{if(r)throw new Error("Cannot sample a disposed Behavior");return performance.now()},map:e=>{if(r)throw new Error("Cannot map a disposed Behavior");let n=!1;return{sample:()=>{if(n||r)throw new Error("Cannot sample a disposed Behavior");return e(performance.now())},map:s=>t.map(o=>s(e(o))),ap:function(s){return c(this,s)},onChange:()=>()=>{},dispose:()=>{n=!0},get isDisposed(){return n||r}}},ap:function(e){return c(this,e)},onChange:()=>()=>{},dispose:()=>{r=!0},get isDisposed(){return r}};return t}function C(...r){const t=r.slice(0,-1),e=r[r.length-1];let n=!1;const s=new Set,o=[],a=()=>e(...t.map(i=>i.sample())),p=()=>{if(n)return;const i=a();for(const l of s)l(i)};for(const i of t){const l=i.onChange(()=>{p()});o.push(l)}const u={sample:()=>{if(n)throw new Error("Cannot sample a disposed Behavior");return a()},map:i=>b(u,i),ap:function(i){return f(this,i)},onChange:i=>n?()=>{}:(s.add(i),()=>s.delete(i)),dispose:()=>{if(!n){n=!0,s.clear();for(const i of o)i();o.length=0}},get isDisposed(){return n}};return u}function b(r,t){let e=!1;const n=new Set,s=()=>t(r.sample()),o=()=>{if(e)return;const u=s();for(const i of n)i(u)},a=r.onChange(()=>o()),p={sample:()=>{if(e)throw new Error("Cannot sample a disposed Behavior");return s()},map:u=>b(p,u),ap:function(u){return f(this,u)},onChange:u=>e?()=>{}:(n.add(u),()=>n.delete(u)),dispose:()=>{e||(e=!0,n.clear(),a())},get isDisposed(){return e}};return p}function f(r,t){let e=!1;const n=new Set,s=()=>r.sample()(t.sample()),o=()=>{if(e)return;const i=s();for(const l of n)l(i)},a=r.onChange(()=>o()),p=t.onChange(()=>o());return{sample:()=>{if(e)throw new Error("Cannot sample a disposed Behavior");return s()},map:i=>f(r.map(l=>d=>i(l(d))),t),ap:function(i){return f(this,i)},onChange:i=>e?()=>{}:(n.add(i),()=>n.delete(i)),dispose:()=>{e||(e=!0,n.clear(),a(),p())},get isDisposed(){return e}}}function E(r,t,e){let n=!1;const s=new Set,o=()=>r.sample()?t.sample():e.sample(),a=()=>{if(n)return;const d=o();for(const S of s)S(d)},p=r.onChange(()=>a()),u=t.onChange(()=>{r.sample()&&a()}),i=e.onChange(()=>{r.sample()||a()});return{sample:()=>{if(n)throw new Error("Cannot sample a disposed Behavior");return o()},map:d=>E(r,t.map(d),e.map(d)),ap:function(d){return f(this,d)},onChange:d=>n?()=>{}:(s.add(d),()=>s.delete(d)),dispose:()=>{n||(n=!0,s.clear(),p(),u(),i())},get isDisposed(){return n}}}function A(r){return(...t)=>{if(t.length===1)return t[0].map(r);if(t.length===2)return C(t[0],t[1],(e,n)=>r(e,n));if(t.length===3)return C(t[0],t[1],t[2],(e,n,s)=>r(e,n,s));throw new Error("lift supports up to 3 behaviors. Use combine() directly for more.")}}function L(r){return m.createStream(t=>{const e=r.onChange(n=>{t.next(h.createSignal("behavior-change",n))});return()=>{e()}})}function q(r,t){return m.createStream(e=>{const n=setInterval(()=>{r.isDisposed||e.next(h.createSignal("sampled",r.sample()))},t);return()=>{clearInterval(n)}})}function x(r,t){return m.createStream(e=>t.on(s=>{r.isDisposed||e.next(h.createSignal("sampled-on",{value:r.sample(),trigger:s}))}))}function I(r){return m.createStream(t=>{let e=!0,n;const s=o=>{e&&(r.isDisposed||t.next(h.createSignal("frame",{value:r.sample(),timestamp:o})),n=requestAnimationFrame(s))};return n=requestAnimationFrame(s),()=>{e=!1,cancelAnimationFrame(n)}})}function O(){const r=performance.now();let t=0,e=!1,n;const s=new Set,o=()=>{if(!e){t=performance.now()-r;for(const p of s)p(t);n=requestAnimationFrame(o)}};n=requestAnimationFrame(o);const a={sample:()=>{if(e)throw new Error("Cannot sample a disposed Behavior");return performance.now()-r},map:p=>D(a,p),ap:function(p){return B(this,p)},onChange:p=>e?()=>{}:(s.add(p),()=>s.delete(p)),dispose:()=>{e||(e=!0,cancelAnimationFrame(n),s.clear())},get isDisposed(){return e}};return{elapsed:a,dispose:()=>a.dispose()}}function D(r,t){let e=!1;const n=new Set,s=r.onChange(a=>{if(e)return;const p=t(a);for(const u of n)u(p)}),o={sample:()=>{if(e||r.isDisposed)throw new Error("Cannot sample a disposed Behavior");return t(r.sample())},map:a=>D(o,a),ap:function(a){return B(this,a)},onChange:a=>e?()=>{}:(n.add(a),()=>n.delete(a)),dispose:()=>{e||(e=!0,s(),n.clear())},get isDisposed(){return e}};return o}function B(r,t){let e=!1;const n=new Set,s=()=>{if(e)return;const u=r.sample()(t.sample());for(const i of n)i(u)},o=r.onChange(s),a=t.onChange(s),p={sample:()=>{if(e)throw new Error("Cannot sample a disposed Behavior");return r.sample()(t.sample())},map:u=>D(p,u),ap:function(u){return B(this,u)},onChange:u=>e?()=>{}:(n.add(u),()=>n.delete(u)),dispose:()=>{e||(e=!0,o(),a(),n.clear())},get isDisposed(){return e}};return p}exports.animationFrame=I;exports.changes=L;exports.combine=C;exports.constant=g;exports.elapsedTime=O;exports.lift=A;exports.sample=q;exports.sampleOn=x;exports.stepper=y;exports.switcher=E;exports.time=F;
|
|
2
|
+
//# sourceMappingURL=frp.cjs.map
|
package/dist/frp.cjs.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"frp.cjs","sources":["../src/frp/behavior.ts","../src/frp/combinators.ts","../src/frp/conversions.ts"],"sourcesContent":["import type { Signal, Stream } from \"../core/index.js\";\n\n/**\n * Behavior represents a value that changes continuously over time.\n * Unlike Stream (Event), Behavior always has a current value that can be sampled.\n *\n * Key concepts:\n * - sample(): Get the current value at any point in time\n * - map(): Transform the value (Functor)\n * - ap(): Apply a function behavior to this behavior (Applicative)\n * - onChange(): Subscribe to value changes (Push notification)\n * - dispose(): Clean up resources and subscriptions\n *\n * @typeParam A - The type of the value\n */\nexport interface Behavior<A> {\n /** Sample the current value */\n sample(): A;\n\n /** Transform the value (Functor map) */\n map<B>(f: (a: A) => B): Behavior<B>;\n\n /**\n * Apply a function from another Behavior to this value (Applicative apply)\n * Note: The function behavior is the receiver, value behavior is the argument\n */\n ap<B>(this: Behavior<(b: B) => A>, bb: Behavior<B>): Behavior<A>;\n\n /** Subscribe to value changes. Returns an unsubscribe function. */\n onChange(callback: (a: A) => void): () => void;\n\n /** Dispose the behavior and clean up all resources */\n dispose(): void;\n\n /** Returns true if the behavior has been disposed */\n readonly isDisposed: boolean;\n}\n\n/**\n * Internal helper to create a base behavior with common functionality.\n * Manages listener set and disposed state.\n */\nfunction createBaseBehavior<A>(\n getSample: () => A,\n onDispose?: () => void,\n): {\n behavior: Omit<Behavior<A>, \"map\" | \"ap\">;\n listeners: Set<(a: A) => void>;\n notifyListeners: () => void;\n isDisposed: () => boolean;\n} {\n const listeners = new Set<(a: A) => void>();\n let disposed = false;\n\n const notifyListeners = () => {\n if (disposed) return;\n const value = getSample();\n for (const listener of listeners) {\n listener(value);\n }\n };\n\n return {\n behavior: {\n sample: () => {\n if (disposed) {\n throw new Error(\"Cannot sample a disposed Behavior\");\n }\n return getSample();\n },\n onChange: (callback) => {\n if (disposed) return () => {};\n listeners.add(callback);\n return () => listeners.delete(callback);\n },\n dispose: () => {\n if (disposed) return;\n disposed = true;\n listeners.clear();\n onDispose?.();\n },\n get isDisposed() {\n return disposed;\n },\n },\n listeners,\n notifyListeners,\n isDisposed: () => disposed,\n };\n}\n\n/**\n * Creates a constant Behavior that never changes.\n * The value is fixed at creation time.\n *\n * @example\n * const always42 = constant(42);\n * always42.sample(); // 42\n */\nexport function constant<A>(value: A): Behavior<A> {\n let disposed = false;\n\n const behavior: Behavior<A> = {\n sample: () => {\n if (disposed) {\n throw new Error(\"Cannot sample a disposed Behavior\");\n }\n return value;\n },\n map: <B>(f: (a: A) => B): Behavior<B> => {\n if (disposed) {\n throw new Error(\"Cannot map a disposed Behavior\");\n }\n return constant(f(value));\n },\n ap: function <B>(this: Behavior<(b: B) => A>, bb: Behavior<B>): Behavior<A> {\n if (disposed) {\n throw new Error(\"Cannot apply a disposed Behavior\");\n }\n return constant(this.sample()(bb.sample()));\n },\n onChange: () => () => {},\n dispose: () => {\n disposed = true;\n },\n get isDisposed() {\n return disposed;\n },\n };\n\n return behavior;\n}\n\n/**\n * Creates a Behavior from an event stream with an initial value.\n * The behavior holds the latest value from the stream.\n *\n * @param initial - The initial value before any events\n * @param event - The event stream to listen to\n * @param selector - Function to extract the value from each signal\n *\n * @example\n * const position = stepper(\n * { x: 0, y: 0 },\n * pointerStream,\n * (signal) => signal.value.position\n * );\n */\nexport function stepper<A, S extends Signal>(\n initial: A,\n event: Stream<S>,\n selector: (signal: S) => A,\n): Behavior<A> {\n let current = initial;\n let unsub: (() => void) | null = null;\n\n const { behavior, notifyListeners, isDisposed } = createBaseBehavior(\n () => current,\n () => {\n unsub?.();\n unsub = null;\n },\n );\n\n unsub = event.on((signal) => {\n if (isDisposed()) return;\n const newValue = selector(signal);\n if (!Object.is(newValue, current)) {\n current = newValue;\n notifyListeners();\n }\n });\n\n const fullBehavior: Behavior<A> = {\n sample: behavior.sample,\n onChange: behavior.onChange,\n dispose: behavior.dispose,\n get isDisposed() {\n return behavior.isDisposed;\n },\n map: <B>(f: (a: A) => B): Behavior<B> => {\n return mappedBehavior(fullBehavior, f);\n },\n ap: function <B>(this: Behavior<(b: B) => A>, bb: Behavior<B>): Behavior<A> {\n return appliedBehavior(this, bb);\n },\n };\n\n return fullBehavior;\n}\n\n/**\n * Creates a mapped Behavior that transforms values from a source behavior.\n */\nfunction mappedBehavior<A, B>(source: Behavior<A>, f: (a: A) => B): Behavior<B> {\n const { behavior, notifyListeners, isDisposed } = createBaseBehavior(\n () => f(source.sample()),\n () => {\n sourceUnsub?.();\n },\n );\n\n const sourceUnsub: (() => void) | null = source.onChange(() => {\n if (!isDisposed()) {\n notifyListeners();\n }\n });\n\n const fullBehavior: Behavior<B> = {\n sample: behavior.sample,\n onChange: behavior.onChange,\n dispose: behavior.dispose,\n get isDisposed() {\n return behavior.isDisposed;\n },\n map: <C>(g: (b: B) => C): Behavior<C> => {\n return mappedBehavior(fullBehavior, g);\n },\n ap: function <C>(this: Behavior<(c: C) => B>, bc: Behavior<C>): Behavior<B> {\n return appliedBehavior(this, bc);\n },\n };\n\n return fullBehavior;\n}\n\n/**\n * Creates an applied Behavior from a function behavior and value behavior.\n */\nfunction appliedBehavior<A, B>(bf: Behavior<(a: A) => B>, ba: Behavior<A>): Behavior<B> {\n const { behavior, notifyListeners, isDisposed } = createBaseBehavior(\n () => bf.sample()(ba.sample()),\n () => {\n unsubF?.();\n unsubA?.();\n },\n );\n\n const unsubF: (() => void) | null = bf.onChange(() => {\n if (!isDisposed()) {\n notifyListeners();\n }\n });\n\n const unsubA: (() => void) | null = ba.onChange(() => {\n if (!isDisposed()) {\n notifyListeners();\n }\n });\n\n const fullBehavior: Behavior<B> = {\n sample: behavior.sample,\n onChange: behavior.onChange,\n dispose: behavior.dispose,\n get isDisposed() {\n return behavior.isDisposed;\n },\n map: <C>(g: (b: B) => C): Behavior<C> => {\n return mappedBehavior(fullBehavior, g);\n },\n ap: function <C>(this: Behavior<(c: C) => B>, bc: Behavior<C>): Behavior<B> {\n return appliedBehavior(this, bc);\n },\n };\n\n return fullBehavior;\n}\n\n/**\n * Creates a Behavior that represents the current time.\n * Each sample() call returns the current timestamp (performance.now()).\n *\n * Note: onChange() is not meaningful for time as it always changes.\n * Use animationFrame() from conversions if you need time-based events.\n *\n * @example\n * const t = time();\n * const now = t.sample(); // current timestamp\n */\nexport function time(): Behavior<number> {\n let disposed = false;\n\n const behavior: Behavior<number> = {\n sample: () => {\n if (disposed) {\n throw new Error(\"Cannot sample a disposed Behavior\");\n }\n return performance.now();\n },\n map: <B>(f: (t: number) => B): Behavior<B> => {\n if (disposed) {\n throw new Error(\"Cannot map a disposed Behavior\");\n }\n // Return a new behavior that samples time and transforms\n let innerDisposed = false;\n return {\n sample: () => {\n if (innerDisposed || disposed) {\n throw new Error(\"Cannot sample a disposed Behavior\");\n }\n return f(performance.now());\n },\n map: (g) => behavior.map((t) => g(f(t))),\n ap: function <C>(this: Behavior<(c: C) => B>, bc: Behavior<C>): Behavior<B> {\n return appliedBehavior(this, bc);\n },\n onChange: () => () => {},\n dispose: () => {\n innerDisposed = true;\n },\n get isDisposed() {\n return innerDisposed || disposed;\n },\n };\n },\n ap: function <B>(this: Behavior<(b: B) => number>, bb: Behavior<B>): Behavior<number> {\n return appliedBehavior(this, bb);\n },\n onChange: () => () => {},\n dispose: () => {\n disposed = true;\n },\n get isDisposed() {\n return disposed;\n },\n };\n\n return behavior;\n}\n","import type { Behavior } from \"./behavior.js\";\n\n/**\n * Combines multiple Behaviors into one using a combining function.\n * The result updates whenever any source behavior changes.\n *\n * @example\n * const transform = combine(\n * positionBehavior,\n * scaleBehavior,\n * rotationBehavior,\n * (pos, scale, rot) => ({ pos, scale, rot })\n * );\n */\nexport function combine<A, B, R>(a: Behavior<A>, b: Behavior<B>, f: (a: A, b: B) => R): Behavior<R>;\n\nexport function combine<A, B, C, R>(\n a: Behavior<A>,\n b: Behavior<B>,\n c: Behavior<C>,\n f: (a: A, b: B, c: C) => R,\n): Behavior<R>;\n\nexport function combine<A, B, C, D, R>(\n a: Behavior<A>,\n b: Behavior<B>,\n c: Behavior<C>,\n d: Behavior<D>,\n f: (a: A, b: B, c: C, d: D) => R,\n): Behavior<R>;\n\nexport function combine<A, B, C, D, E, R>(\n a: Behavior<A>,\n b: Behavior<B>,\n c: Behavior<C>,\n d: Behavior<D>,\n e: Behavior<E>,\n f: (a: A, b: B, c: C, d: D, e: E) => R,\n): Behavior<R>;\n\nexport function combine(...args: unknown[]): Behavior<unknown> {\n const behaviors = args.slice(0, -1) as Behavior<unknown>[];\n const f = args[args.length - 1] as (...values: unknown[]) => unknown;\n\n let disposed = false;\n const listeners = new Set<(value: unknown) => void>();\n const unsubscribes: (() => void)[] = [];\n\n const sample = () => f(...behaviors.map((b) => b.sample()));\n\n const notifyListeners = () => {\n if (disposed) return;\n const value = sample();\n for (const listener of listeners) {\n listener(value);\n }\n };\n\n // Subscribe to all source behaviors\n for (const behavior of behaviors) {\n const unsub = behavior.onChange(() => {\n notifyListeners();\n });\n unsubscribes.push(unsub);\n }\n\n const combinedBehavior: Behavior<unknown> = {\n sample: () => {\n if (disposed) {\n throw new Error(\"Cannot sample a disposed Behavior\");\n }\n return sample();\n },\n\n map: <B>(g: (r: unknown) => B): Behavior<B> => {\n return mappedCombine(combinedBehavior, g);\n },\n\n ap: function <B>(this: Behavior<(b: B) => unknown>, bb: Behavior<B>): Behavior<unknown> {\n return appliedCombine(this, bb);\n },\n\n onChange: (callback) => {\n if (disposed) return () => {};\n listeners.add(callback);\n return () => listeners.delete(callback);\n },\n\n dispose: () => {\n if (disposed) return;\n disposed = true;\n listeners.clear();\n for (const unsub of unsubscribes) {\n unsub();\n }\n unsubscribes.length = 0;\n },\n\n get isDisposed() {\n return disposed;\n },\n };\n\n return combinedBehavior;\n}\n\n/**\n * Helper for mapping a combined behavior\n */\nfunction mappedCombine<A, B>(source: Behavior<A>, f: (a: A) => B): Behavior<B> {\n let disposed = false;\n const listeners = new Set<(value: B) => void>();\n\n const sample = () => f(source.sample());\n\n const notifyListeners = () => {\n if (disposed) return;\n const value = sample();\n for (const listener of listeners) {\n listener(value);\n }\n };\n\n const unsub = source.onChange(() => notifyListeners());\n\n const behavior: Behavior<B> = {\n sample: () => {\n if (disposed) {\n throw new Error(\"Cannot sample a disposed Behavior\");\n }\n return sample();\n },\n map: <C>(g: (b: B) => C): Behavior<C> => {\n return mappedCombine(behavior, g);\n },\n ap: function <C>(this: Behavior<(c: C) => B>, bc: Behavior<C>): Behavior<B> {\n return appliedCombine(this, bc);\n },\n onChange: (callback) => {\n if (disposed) return () => {};\n listeners.add(callback);\n return () => listeners.delete(callback);\n },\n dispose: () => {\n if (disposed) return;\n disposed = true;\n listeners.clear();\n unsub();\n },\n get isDisposed() {\n return disposed;\n },\n };\n\n return behavior;\n}\n\n/**\n * Helper for ap on combined behaviors\n */\nfunction appliedCombine<A, B>(bf: Behavior<(a: A) => B>, ba: Behavior<A>): Behavior<B> {\n let disposed = false;\n const listeners = new Set<(value: B) => void>();\n\n const sample = () => bf.sample()(ba.sample());\n\n const notifyListeners = () => {\n if (disposed) return;\n const value = sample();\n for (const listener of listeners) {\n listener(value);\n }\n };\n\n const unsubF = bf.onChange(() => notifyListeners());\n const unsubA = ba.onChange(() => notifyListeners());\n\n const behavior: Behavior<B> = {\n sample: () => {\n if (disposed) {\n throw new Error(\"Cannot sample a disposed Behavior\");\n }\n return sample();\n },\n map: <C>(g: (b: B) => C): Behavior<C> => {\n return appliedCombine(\n bf.map((f) => (a: A) => g(f(a))),\n ba,\n );\n },\n ap: function <C>(this: Behavior<(c: C) => B>, bc: Behavior<C>): Behavior<B> {\n return appliedCombine(this, bc);\n },\n onChange: (callback) => {\n if (disposed) return () => {};\n listeners.add(callback);\n return () => listeners.delete(callback);\n },\n dispose: () => {\n if (disposed) return;\n disposed = true;\n listeners.clear();\n unsubF();\n unsubA();\n },\n get isDisposed() {\n return disposed;\n },\n };\n\n return behavior;\n}\n\n/**\n * Selects between two Behaviors based on a boolean condition Behavior.\n * When condition is true, samples from ifTrue; otherwise from ifFalse.\n *\n * @example\n * const displayValue = switcher(\n * isEditMode,\n * editableValue,\n * readonlyValue\n * );\n */\nexport function switcher<A>(\n condition: Behavior<boolean>,\n ifTrue: Behavior<A>,\n ifFalse: Behavior<A>,\n): Behavior<A> {\n let disposed = false;\n const listeners = new Set<(value: A) => void>();\n\n const sample = () => (condition.sample() ? ifTrue.sample() : ifFalse.sample());\n\n const notifyListeners = () => {\n if (disposed) return;\n const value = sample();\n for (const listener of listeners) {\n listener(value);\n }\n };\n\n const unsubCond = condition.onChange(() => notifyListeners());\n const unsubTrue = ifTrue.onChange(() => {\n if (condition.sample()) notifyListeners();\n });\n const unsubFalse = ifFalse.onChange(() => {\n if (!condition.sample()) notifyListeners();\n });\n\n const behavior: Behavior<A> = {\n sample: () => {\n if (disposed) {\n throw new Error(\"Cannot sample a disposed Behavior\");\n }\n return sample();\n },\n map: <B>(f: (a: A) => B): Behavior<B> => {\n return switcher(condition, ifTrue.map(f), ifFalse.map(f));\n },\n ap: function <B>(this: Behavior<(b: B) => A>, bb: Behavior<B>): Behavior<A> {\n return appliedCombine(this, bb);\n },\n onChange: (callback) => {\n if (disposed) return () => {};\n listeners.add(callback);\n return () => listeners.delete(callback);\n },\n dispose: () => {\n if (disposed) return;\n disposed = true;\n listeners.clear();\n unsubCond();\n unsubTrue();\n unsubFalse();\n },\n get isDisposed() {\n return disposed;\n },\n };\n\n return behavior;\n}\n\n/**\n * Lifts a pure function to work with Behaviors.\n * Equivalent to combining behaviors and applying a function.\n *\n * @example\n * const add = (a: number, b: number) => a + b;\n * const sumBehavior = lift(add)(behaviorA, behaviorB);\n */\nexport function lift<A, R>(f: (a: A) => R): (ba: Behavior<A>) => Behavior<R>;\nexport function lift<A, B, R>(\n f: (a: A, b: B) => R,\n): (ba: Behavior<A>, bb: Behavior<B>) => Behavior<R>;\nexport function lift<A, B, C, R>(\n f: (a: A, b: B, c: C) => R,\n): (ba: Behavior<A>, bb: Behavior<B>, bc: Behavior<C>) => Behavior<R>;\n\nexport function lift(f: (...args: unknown[]) => unknown) {\n return (...behaviors: Behavior<unknown>[]) => {\n if (behaviors.length === 1) {\n return behaviors[0].map(f);\n }\n // Use explicit overload calls to avoid spread type issues\n if (behaviors.length === 2) {\n return combine(behaviors[0], behaviors[1], (a, b) => f(a, b));\n }\n if (behaviors.length === 3) {\n return combine(behaviors[0], behaviors[1], behaviors[2], (a, b, c) => f(a, b, c));\n }\n // For 4+ arguments, fall through to variadic combine\n // This requires explicit handling due to TypeScript limitations\n throw new Error(\"lift supports up to 3 behaviors. Use combine() directly for more.\");\n };\n}\n","import { createSignal, createStream, type Signal, type Stream } from \"../core/index.js\";\nimport type { Behavior } from \"./behavior.js\";\n\n/**\n * Signal type for behavior change events\n */\nexport type BehaviorChangeSignal<A> = Signal<\"behavior-change\", A>;\n\n/**\n * Signal type for sampled values\n */\nexport type SampledSignal<A> = Signal<\"sampled\", A>;\n\n/**\n * Signal type for animation frame samples\n */\nexport type FrameSignal<A> = Signal<\"frame\", { value: A; timestamp: number }>;\n\n/**\n * Converts a Behavior to an Event (Stream) that fires when the value changes.\n * This is the Behavior → Event conversion.\n *\n * @param behavior - The behavior to observe\n * @returns A stream that emits signals whenever the behavior's value changes\n *\n * @example\n * const positionChanges = changes(positionBehavior);\n * positionChanges.on(signal => {\n * console.log('Position changed to:', signal.value);\n * });\n */\nexport function changes<A>(behavior: Behavior<A>): Stream<BehaviorChangeSignal<A>> {\n return createStream((observer) => {\n const unsub = behavior.onChange((value) => {\n observer.next(createSignal(\"behavior-change\", value));\n });\n\n return () => {\n unsub();\n };\n });\n}\n\n/**\n * Samples a Behavior at regular intervals.\n *\n * @param behavior - The behavior to sample\n * @param intervalMs - The sampling interval in milliseconds\n * @returns A stream that emits the sampled value at each interval\n *\n * @example\n * const positionSamples = sample(positionBehavior, 16); // ~60fps\n * positionSamples.on(signal => {\n * updateDisplay(signal.value);\n * });\n */\nexport function sample<A>(behavior: Behavior<A>, intervalMs: number): Stream<SampledSignal<A>> {\n return createStream((observer) => {\n const id = setInterval(() => {\n if (!behavior.isDisposed) {\n observer.next(createSignal(\"sampled\", behavior.sample()));\n }\n }, intervalMs);\n\n return () => {\n clearInterval(id);\n };\n });\n}\n\n/**\n * Samples a Behavior whenever another event occurs.\n * Useful for getting the current state at specific moments.\n *\n * @param behavior - The behavior to sample\n * @param trigger - The trigger event stream\n * @returns A stream that emits the sampled value along with the trigger signal\n *\n * @example\n * const positionOnClick = sampleOn(positionBehavior, clickStream);\n * positionOnClick.on(signal => {\n * console.log('Position at click:', signal.value.value);\n * console.log('Click event:', signal.value.trigger);\n * });\n */\nexport function sampleOn<A, S extends Signal>(\n behavior: Behavior<A>,\n trigger: Stream<S>,\n): Stream<Signal<\"sampled-on\", { value: A; trigger: S }>> {\n return createStream((observer) => {\n const unsub = trigger.on((signal) => {\n if (!behavior.isDisposed) {\n observer.next(\n createSignal(\"sampled-on\", {\n value: behavior.sample(),\n trigger: signal,\n }),\n );\n }\n });\n\n return unsub;\n });\n}\n\n/**\n * Samples a Behavior on every animation frame using requestAnimationFrame.\n * Ideal for rendering loops and smooth animations.\n *\n * @param behavior - The behavior to sample\n * @returns A stream that emits on each animation frame with the sampled value and timestamp\n *\n * @example\n * const frameStream = animationFrame(transformBehavior);\n * frameStream.on(({ value }) => {\n * element.style.transform = `translate(${value.x}px, ${value.y}px)`;\n * });\n */\nexport function animationFrame<A>(behavior: Behavior<A>): Stream<FrameSignal<A>> {\n return createStream((observer) => {\n let running = true;\n let frameId: number;\n\n const loop = (timestamp: number) => {\n if (!running) return;\n\n if (!behavior.isDisposed) {\n observer.next(\n createSignal(\"frame\", {\n value: behavior.sample(),\n timestamp,\n }),\n );\n }\n\n frameId = requestAnimationFrame(loop);\n };\n\n frameId = requestAnimationFrame(loop);\n\n return () => {\n running = false;\n cancelAnimationFrame(frameId);\n };\n });\n}\n\n/**\n * Creates a Behavior that tracks elapsed time since creation.\n * The elapsed time is updated on each animation frame.\n *\n * Note: This returns both a Behavior and a dispose function.\n * Call dispose() when you no longer need the elapsed time tracking.\n *\n * @returns Object containing the elapsed behavior and dispose function\n *\n * @example\n * const { elapsed, dispose } = elapsedTime();\n * // Use elapsed.sample() to get time since creation\n * // Call dispose() when done\n */\nexport function elapsedTime(): { elapsed: Behavior<number>; dispose: () => void } {\n const startTime = performance.now();\n let currentElapsed = 0;\n let disposed = false;\n let frameId: number;\n const listeners = new Set<(value: number) => void>();\n\n const loop = () => {\n if (disposed) return;\n currentElapsed = performance.now() - startTime;\n for (const listener of listeners) {\n listener(currentElapsed);\n }\n frameId = requestAnimationFrame(loop);\n };\n\n frameId = requestAnimationFrame(loop);\n\n const elapsed: Behavior<number> = {\n sample: () => {\n if (disposed) {\n throw new Error(\"Cannot sample a disposed Behavior\");\n }\n return performance.now() - startTime;\n },\n map: <B>(f: (t: number) => B): Behavior<B> => {\n return mappedElapsed(elapsed, f);\n },\n ap: function <B>(this: Behavior<(b: B) => number>, bb: Behavior<B>): Behavior<number> {\n return appliedElapsed(this, bb);\n },\n onChange: (callback) => {\n if (disposed) return () => {};\n listeners.add(callback);\n return () => listeners.delete(callback);\n },\n dispose: () => {\n if (disposed) return;\n disposed = true;\n cancelAnimationFrame(frameId);\n listeners.clear();\n },\n get isDisposed() {\n return disposed;\n },\n };\n\n return {\n elapsed,\n dispose: () => elapsed.dispose(),\n };\n}\n\nfunction mappedElapsed<A, B>(source: Behavior<A>, f: (a: A) => B): Behavior<B> {\n let disposed = false;\n const listeners = new Set<(value: B) => void>();\n\n const unsub = source.onChange((value) => {\n if (disposed) return;\n const mapped = f(value);\n for (const listener of listeners) {\n listener(mapped);\n }\n });\n\n const behavior: Behavior<B> = {\n sample: () => {\n if (disposed || source.isDisposed) {\n throw new Error(\"Cannot sample a disposed Behavior\");\n }\n return f(source.sample());\n },\n map: <C>(g: (b: B) => C): Behavior<C> => {\n return mappedElapsed(behavior, g);\n },\n ap: function <C>(this: Behavior<(c: C) => B>, bc: Behavior<C>): Behavior<B> {\n return appliedElapsed(this, bc);\n },\n onChange: (callback) => {\n if (disposed) return () => {};\n listeners.add(callback);\n return () => listeners.delete(callback);\n },\n dispose: () => {\n if (disposed) return;\n disposed = true;\n unsub();\n listeners.clear();\n },\n get isDisposed() {\n return disposed;\n },\n };\n\n return behavior;\n}\n\nfunction appliedElapsed<A, B>(bf: Behavior<(a: A) => B>, ba: Behavior<A>): Behavior<B> {\n let disposed = false;\n const listeners = new Set<(value: B) => void>();\n\n const notify = () => {\n if (disposed) return;\n const value = bf.sample()(ba.sample());\n for (const listener of listeners) {\n listener(value);\n }\n };\n\n const unsubF = bf.onChange(notify);\n const unsubA = ba.onChange(notify);\n\n const behavior: Behavior<B> = {\n sample: () => {\n if (disposed) {\n throw new Error(\"Cannot sample a disposed Behavior\");\n }\n return bf.sample()(ba.sample());\n },\n map: <C>(g: (b: B) => C): Behavior<C> => {\n return mappedElapsed(behavior, g);\n },\n ap: function <C>(this: Behavior<(c: C) => B>, bc: Behavior<C>): Behavior<B> {\n return appliedElapsed(this, bc);\n },\n onChange: (callback) => {\n if (disposed) return () => {};\n listeners.add(callback);\n return () => listeners.delete(callback);\n },\n dispose: () => {\n if (disposed) return;\n disposed = true;\n unsubF();\n unsubA();\n listeners.clear();\n },\n get isDisposed() {\n return disposed;\n },\n };\n\n return behavior;\n}\n"],"names":["createBaseBehavior","getSample","onDispose","listeners","disposed","callback","value","listener","constant","f","bb","stepper","initial","event","selector","current","unsub","behavior","notifyListeners","isDisposed","signal","newValue","fullBehavior","mappedBehavior","appliedBehavior","source","sourceUnsub","g","bc","bf","ba","unsubF","unsubA","time","innerDisposed","t","combine","args","behaviors","unsubscribes","sample","b","combinedBehavior","mappedCombine","appliedCombine","a","switcher","condition","ifTrue","ifFalse","unsubCond","unsubTrue","unsubFalse","lift","c","changes","createStream","observer","createSignal","intervalMs","id","sampleOn","trigger","animationFrame","running","frameId","loop","timestamp","elapsedTime","startTime","currentElapsed","elapsed","mappedElapsed","appliedElapsed","mapped","notify"],"mappings":"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"}
|
package/dist/frp.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FRP (Functional Reactive Programming) module for Cereb.
|
|
3
|
+
*
|
|
4
|
+
* This module introduces the classic FRP concepts:
|
|
5
|
+
* - Behavior: Continuous time-varying values (always has a current value)
|
|
6
|
+
* - Event: Discrete occurrences (alias for Stream)
|
|
7
|
+
*
|
|
8
|
+
* Key differences from Stream:
|
|
9
|
+
* - Behavior.sample() - Get current value anytime
|
|
10
|
+
* - Behavior.onChange() - Subscribe to value changes
|
|
11
|
+
* - Behavior.dispose() - Clean up resources
|
|
12
|
+
*
|
|
13
|
+
* Use cases:
|
|
14
|
+
* - Animation frames that need current position/scale/rotation
|
|
15
|
+
* - VR headset tracking with continuous position sampling
|
|
16
|
+
* - Combining multiple input sources into a unified transform
|
|
17
|
+
*
|
|
18
|
+
* @module cereb/frp
|
|
19
|
+
*/
|
|
20
|
+
export * from './frp/index.js';
|
|
21
|
+
//# sourceMappingURL=frp.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"frp.d.ts","sourceRoot":"","sources":["../src/frp.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AACH,cAAc,gBAAgB,CAAC"}
|