@fest-lib/object 0.1.19 → 0.1.20

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.
Files changed (2) hide show
  1. package/README.md +77 -372
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -1,420 +1,125 @@
1
- # Object.TS
2
-
3
- `@fest-lib/object`reactive proxies, refs, computed/derived values, and collection observe for fest-lib. Sits above `@fest-lib/core`. LUR.E and FL.UI subscribe through `affected`.
4
-
5
- <img src="https://img.shields.io/github/license/fest-live/object.ts?style=flat-square" alt="License"> <img src="https://img.shields.io/github/stars/fest-live/object.ts?style=flat-square" alt="Stars"> <img src="https://img.shields.io/github/last-commit/fest-live/object.ts?style=flat-square" alt="Last Commit">
6
-
7
- [![npm version](https://img.shields.io/npm/v/@fest-lib/object?style=flat-square)](https://www.npmjs.com/package/@fest-lib/object)
8
- [![Build Status](https://img.shields.io/github/actions/workflow/status/fest-live/object.ts/ci.yml?branch=main&style=flat-square)](https://github.com/fest-live/object.ts/actions)
9
- [![Coverage Status](https://img.shields.io/codecov/c/github/fest-live/object.ts?style=flat-square)](https://codecov.io/gh/fest-live/object.ts)
10
-
11
- Subscriptions do not retain the target. Updates fire only on actual value changes.
12
-
13
- ## Table of Contents
14
-
15
- - [Features](#features)
16
- - [Installation](#installation)
17
- - [Usage](#usage)
18
- - [API Reference](#api-reference)
19
- - [Reactivity](#reactivity)
20
- - [DOM Utilities](#dom-utilities)
21
- - [Related Projects](#related-projects)
22
- - [License](#license)
23
-
24
- ---
25
-
26
- ## Features
27
-
28
- - **Non-intrusive subscriptions:** Subscribers do not retain references to target objects.
29
- - **Efficient reactivity:** Triggers only on actual value changes.
30
- - **Compatibility:** Works with recent versions of popular reactive libraries.
31
-
32
- ---
33
-
34
- ## Usage & Examples
35
-
36
- ### Reactivity (basics)
37
-
38
- - **`observe(initial)`**
39
- Creates a reactive primitive from an existing object, array, Set, or Map.
40
-
41
- - **`affected(obj, callback)`**
42
- Subscribes to changes in an observable object, `Set`, or `Map`.
43
- - Supports `[obj, key]` to subscribe to a specific property.
44
- - Returns an unsubscribe function.
45
-
46
- - **`ref(initial)`**
47
- Creates an observable reference with a `value` property.
48
-
49
- - **`computed(src, cb, behavior, prop)`**
50
- Creates a computed reactive value from a source.
51
- - Computes its value using a callback function.
52
- - Automatically updates when dependencies change.
53
-
54
- - **`conditional(cond, ifTrue, ifFalse)`**
55
- Reactive value that switches between `ifTrue` and `ifFalse` based on `cond.value`.
1
+ <p align="center">
2
+ <strong>@fest-lib/object</strong><br>
3
+ Level 1 observe / affected / refs. LUR.E and FL.UI subscribe through <code>affected</code>.
4
+ </p>
5
+
6
+ <p align="center">
7
+ <a href="https://www.npmjs.com/package/@fest-lib/object"><img src="https://img.shields.io/npm/v/@fest-lib/object?style=flat-square" alt="npm"></a>
8
+ <a href="LICENSE"><img src="https://img.shields.io/npm/l/@fest-lib/object?style=flat-square" alt="MIT"></a>
9
+ <a href="https://github.com/fest-live/object.ts"><img src="https://img.shields.io/github/stars/fest-live/object.ts?style=flat-square" alt="stars"></a>
10
+ </p>
11
+
12
+ Reactive proxies for objects, arrays, `Set`, and `Map`. Subscriptions do **not** retain the target. Updates fire only when the value actually changes.
13
+
14
+ ```text
15
+ core · uniform
16
+ └── fest/object ← you are here
17
+ └── lure · veela · icon · image · fl-ui
18
+ ```
56
19
 
57
- ### Install
20
+ ## Install
58
21
 
59
22
  ```bash
60
- npm i @fest-lib/object
23
+ npm install @fest-lib/core @fest-lib/uniform @fest-lib/object
61
24
  ```
62
25
 
63
- ### Importing
26
+ Peers: `@fest-lib/core`, `@fest-lib/uniform` (`>=0.1.0`). ESM, Node **20+**.
64
27
 
65
28
  ```ts
66
- import {
67
- // Core reactivity
68
- observe,
69
- affected,
70
- makeArrayObservable,
71
- isObservable,
72
- recoverReactive,
29
+ import { observe, affected, ref, computed } from "@fest-lib/object";
73
30
 
74
- // Primitive refs
75
- ref,
76
- numberRef,
77
- stringRef,
78
- booleanRef,
79
- autoRef,
80
- promised,
81
-
82
- // Computed and derived values
83
- computed,
84
- derivate,
85
- conditional,
86
- remap,
87
- unified,
88
-
89
- // Binding and assignment
90
- bindBy,
91
- assign,
92
- link,
93
-
94
- // Collection utilities
95
- observableBySet,
96
- observableByMap,
97
- iterated,
98
-
99
- // Subscription management
100
- unaffected,
101
- triggerWithDelay,
102
- delayedBehavior,
103
- delayedOrInstantBehavior,
104
-
105
- // Utilities
106
- safe,
107
- deref,
108
- unwrap,
109
- propRef,
110
-
111
- // Legacy (deprecated)
112
- createReactive,
113
- createReactiveMap,
114
- createReactiveSet
115
- } from "@fest-lib/object";
116
- ```
117
-
118
- ### Quick start
119
-
120
- ```ts
121
31
  const state = observe({ count: 0, user: { name: "Ada" } });
122
-
123
32
  const stop = affected(state, (value, prop) => {
124
- console.log("changed:", prop, value[prop as keyof typeof value]);
33
+ console.log("changed:", prop, value[prop as keyof typeof value]);
125
34
  });
126
-
127
35
  state.count = 1;
128
36
  stop?.();
129
37
  ```
130
38
 
131
- ### Primitive refs
39
+ ## Features
40
+
41
+ - Non-intrusive subscriptions (disposer from `affected`).
42
+ - `observe` adapts `Set` / `Map` so iteration changes notify.
43
+ - Primitive refs with coercion (`numberRef`, `stringRef`, `booleanRef`).
44
+ - `computed` / `derivate` / `conditional` / `propRef`.
45
+ - `bindBy` / `assign` / `link` for shape sync.
46
+ - `safe()` for JSON (cycles, WeakRef).
47
+
48
+ ## Primitive refs
132
49
 
133
50
  ```ts
51
+ import { numberRef, stringRef, booleanRef, autoRef, promised } from "@fest-lib/object";
52
+
134
53
  const n = numberRef(0);
135
54
  const s = stringRef("hello");
136
55
  const b = booleanRef(false);
56
+ n.value++;
57
+ s.value = `${s}!`;
58
+ b.value = 1; // truthy → true
137
59
 
138
- n.value++; // 1
139
- s.value = s + "!"; // "hello!"
140
- b.value = 1; // true (truthy coercion)
60
+ const later = promised(fetch("/api").then((r) => r.status));
141
61
  ```
142
62
 
143
- #### Auto ref and promised
63
+ `autoRef(true)` / `autoRef(42)` / `autoRef("hi")` pick the matching primitive ref.
144
64
 
145
- ```ts
146
- const r1 = autoRef(true); // booleanRef
147
- const r2 = autoRef(42); // numberRef
148
- const r3 = autoRef("hi"); // stringRef
149
- const r4 = ref<any>({ a: 1 });
150
-
151
- const later = promised(fetch("/api").then(r => r.status));
152
- subscribe(later, () => console.log("ready:", later.value));
153
- ```
154
-
155
- ### Observing collections and properties
65
+ ## Collections
156
66
 
157
67
  ```ts
158
68
  const list = observe([1, 2, 3]);
159
- const bag = observe(new Set(["a", "b"]));
160
- const map = observe(new Map([["x", 1]]));
161
-
162
- const unAll = affected(list, (v, prop) => console.log("list changed", prop));
163
- const unBag = affected(bag, (v, prop) => console.log("set changed", prop));
164
- const unMap = affected(map, (v, prop) => console.log("map changed", prop));
165
-
166
- const person = observe({ name: "Ada", age: 36 });
167
- const unName = affected([person, "name"], (v) => console.log("name:", v));
168
-
169
- person.name = "Grace";
170
- unAll?.(); unBag?.(); unMap?.(); unName?.();
171
- ```
172
-
173
- ### Deriving and binding
174
-
175
- ```ts
176
- const source = observe({ x: 1, y: 2 });
177
-
178
- // Read-only derivative
179
- const sum = derivate(source, s => ({ sum: s.x + s.y }));
180
- affected(sum, () => console.log("sum:", sum.sum));
181
-
182
- // Two-way bind by shape
183
- const target: any = { x: 0, y: 0 };
184
- bindBy(target, source);
69
+ const bag = observe(new Set(["a", "b"]));
70
+ const map = observe(new Map([["x", 1]]));
185
71
 
186
- source.x = 3; // target.x becomes 3
72
+ affected(list, (_v, prop) => console.log("list", prop));
73
+ affected([observe({ name: "Ada" }), "name"], (v) => console.log("name:", v));
187
74
  ```
188
75
 
189
- ### Safe serialization
76
+ `observableBySet` / `observableByMap` expose a reactive array view. `iterated` subscribes to iteration.
190
77
 
191
- ```ts
192
- const complex = observe({ d: new Date(), w: new WeakRef({ a: 1 }) });
193
- JSON.stringify(safe(complex));
194
- ```
195
-
196
- ### Computed values
78
+ ## Derived & bind
197
79
 
198
80
  ```ts
199
- const state = observe({ a: 1, b: 2 });
200
- const sum = computed(state, s => s.a + s.b);
81
+ const source = observe({ x: 1, y: 2 });
82
+ const total = computed(source, (s) => s.x + s.y);
83
+ const view = derivate(source, (s) => ({ sum: s.x + s.y }));
201
84
 
202
- affected(sum, () => console.log("sum changed:", sum.value));
203
- state.a = 3; // triggers: sum changed: 5
85
+ const target = { x: 0, y: 0 };
86
+ bindBy(target, source); // two-way by shape
87
+ source.x = 3; // target.x === 3
204
88
  ```
205
89
 
206
- ### Conditional reactivity
207
-
208
90
  ```ts
209
- const condition = booleanRef(true);
210
- const result = conditional(condition, "yes", "no");
211
-
212
- affected(result, () => console.log("result:", result.value));
213
- condition.value = false; // triggers: result: no
214
- ```
215
-
216
- ### Property references
91
+ const cond = booleanRef(true);
92
+ const pick = conditional(cond, "yes", "no");
93
+ cond.value = false; // pick.value === "no"
217
94
 
218
- ```ts
219
95
  const obj = observe({ nested: { value: 42 } });
220
- const propRef = propRef(obj, "nested.value");
221
-
222
- affected(propRef, () => console.log("nested value:", propRef.value));
223
- obj.nested.value = 100; // triggers: nested value: 100
224
- ```
225
-
226
- ### Collection observables
227
-
228
- ```ts
229
- const set = observe(new Set([1, 2, 3]));
230
- const arrayFromSet = observableBySet(set);
231
-
232
- affected(arrayFromSet, () => console.log("set as array:", arrayFromSet));
233
- set.add(4); // triggers: set as array: [1, 2, 3, 4]
234
- ```
235
-
236
- ### Notes
237
-
238
- - Subscriptions fire only on actual changes.
239
- - `observe` adapts `Set`/`Map` to emit iteration changes.
240
- - To stop listening, keep the disposer returned by `affected` and call it.
241
-
242
- ## API Reference
243
-
244
- ### Core Reactivity
245
-
246
- #### `observe<T>(target: T): observeValid<T>`
247
-
248
- Creates a reactive proxy from an object, array, Set, or Map. Changes to the reactive object will trigger subscriptions.
249
-
250
- ```ts
251
- const obj = observe({ count: 0 });
252
- const arr = observe([1, 2, 3]);
253
- const set = observe(new Set([1, 2]));
96
+ const deep = propRef(obj, "nested.value");
254
97
  ```
255
98
 
256
- #### `affected(obj, callback): UnsubscribeFn`
99
+ ## API map
257
100
 
258
- Subscribes to changes on a reactive object. Returns an unsubscribe function.
101
+ | Group | Exports |
102
+ | --- | --- |
103
+ | Reactivity | `observe`, `affected`, `isObservable`, `recoverReactive`, `makeArrayObservable` |
104
+ | Refs | `ref`, `numberRef`, `stringRef`, `booleanRef`, `autoRef`, `promised`, `propRef` |
105
+ | Derived | `computed`, `derivate`, `conditional`, `remap`, `unified` |
106
+ | Bind | `bindBy`, `assign`, `link` |
107
+ | Collections | `observableBySet`, `observableByMap`, `iterated` |
108
+ | Timing | `triggerWithDelay`, `delayedBehavior`, `delayedOrInstantBehavior` |
109
+ | Utils | `safe`, `deref`, `unwrap`, `unaffected` |
110
+ | Legacy | `createReactive`, `createReactiveMap`, `createReactiveSet` (deprecated) |
259
111
 
260
- ```ts
261
- const state = observe({ count: 0 });
262
- const unsubscribe = affected(state, (value, prop, old) => {
263
- console.log(`${prop} changed from ${old} to ${value[prop]}`);
264
- });
265
- ```
266
-
267
- #### `isObservable(obj): boolean`
268
-
269
- Checks if an object is already reactive.
270
-
271
- #### `recoverReactive(obj): observeValid | null`
272
-
273
- Attempts to recover the reactive version of an object.
274
-
275
- ### Reactive References
276
-
277
- #### `ref<T>(initial: T): Ref<T>`
278
-
279
- Creates a reactive reference with a `.value` property.
280
-
281
- #### `numberRef(initial?: number): NumberRef`
282
-
283
- Creates a reactive number reference with type coercion.
284
-
285
- #### `stringRef(initial?: string): StringRef`
286
-
287
- Creates a reactive string reference with type coercion.
288
-
289
- #### `booleanRef(initial?: boolean): BooleanRef`
290
-
291
- Creates a reactive boolean reference with truthy coercion.
292
-
293
- #### `autoRef(initial: any): Ref`
294
-
295
- Automatically creates the appropriate ref type based on the initial value.
296
-
297
- #### `promised<T>(promise: Promise<T>): PromisedRef<T>`
112
+ `affected(obj, cb)` or `affected([obj, key], cb)` → unsubscribe function. Keep it and call it.
298
113
 
299
- Creates a reactive reference from a Promise.
114
+ Sources: `src/core/Mainline.ts` (subscribe), `Primitives.ts`, `Assigned.ts`, `Subscript.ts`, `src/wrap/*`.
300
115
 
301
- ### Computed Values
116
+ ## Workspace
302
117
 
303
- #### `computed<T>(src, cb, behavior?, prop?): ComputedRef<T>`
304
-
305
- Creates a computed reactive value that updates when its dependencies change.
306
-
307
- ```ts
308
- const state = observe({ a: 1, b: 2 });
309
- const sum = computed(state, s => s.a + s.b);
118
+ ```bash
119
+ cd modules/projects/object.ts
120
+ npm test # node + deno + browser
121
+ npm run build
122
+ npm run publish
310
123
  ```
311
124
 
312
- #### `derivate<T>(from, reactFn, watch?): observeValid`
313
-
314
- Creates a derived reactive object from a source.
315
-
316
- #### `conditional<T>(cond, ifTrue, ifFalse): ConditionalRef<T>`
317
-
318
- Creates a reactive value that switches between two values based on a condition.
319
-
320
- ### Binding & Assignment
321
-
322
- #### `bindBy(target, reactive, watch?)`
323
-
324
- Two-way binds a target object to a reactive source.
325
-
326
- #### `assign<T>(a, b, prop?): UnsubscribeFn`
327
-
328
- Assigns reactive values between objects with automatic synchronization.
329
-
330
- #### `link<T>(a, b, prop?): UnsubscribeFn`
331
-
332
- Creates a bidirectional link between two reactive values.
333
-
334
- ### Collection Utilities
335
-
336
- #### `observableBySet<T>(set: Set<T>): T[]`
337
-
338
- Converts a reactive Set to a reactive array.
339
-
340
- #### `observableByMap<K, V>(map: Map<K, V>): [K, V][]`
341
-
342
- Converts a reactive Map to a reactive array of key-value pairs.
343
-
344
- #### `iterated<T>(target, cb, ctx?): UnsubscribeFn`
345
-
346
- Subscribes to iteration changes on collections.
347
-
348
- #### `makeArrayObservable(target): observeValid`
349
-
350
- Makes arrays observable.
351
-
352
- ### Utilities
353
-
354
- #### `safe(obj): any`
355
-
356
- Prepares an object for JSON serialization by handling circular references and WeakRefs.
357
-
358
- #### `deref(obj): any`
359
-
360
- Dereferences WeakRefs and unwraps reactive objects.
361
-
362
- #### `unwrap(obj): any`
363
-
364
- Unwraps reactive objects to their original form.
365
-
366
- #### `propRef<T>(src, prop, initial?, behavior?): Ref<T>`
367
-
368
- Creates a reactive reference to a specific property.
369
-
370
- ### Subscription Management
371
-
372
- #### `unaffected<T>(target, cb?, ctx?): Promise<T>`
373
-
374
- Removes subscriptions from an object.
375
-
376
- #### `triggerWithDelay(ref, cb, delay?): Timeout`
377
-
378
- Triggers a callback after a delay if the ref value is truthy.
379
-
380
- #### `delayedBehavior(delay?): Function`
381
-
382
- Creates a behavior function that delays execution.
383
-
384
- #### `delayedOrInstantBehavior(delay?): Function`
385
-
386
- Creates a behavior that executes immediately or after delay.
387
-
388
- ### Legacy (Deprecated)
389
-
390
- #### `createReactive(target, stateName?)`
391
-
392
- Legacy function for creating reactive objects.
393
-
394
- #### `createReactiveMap<K, V>(map?): Map<K, V>`
395
-
396
- Legacy function for creating reactive Maps.
397
-
398
- #### `createReactiveSet<V>(set?): Set<V>`
399
-
400
- Legacy function for creating reactive Sets.
401
-
402
- ***
403
-
404
- ## Modules
405
-
406
- - [core/Assigned](src/core/Assigned.ts) - Assignment and binding utilities
407
- - [core/Mainline](src/core/Mainline.ts) - Core subscription and reactivity system
408
- - [core/Primitives](src/core/Primitives.ts) - Primitive reactive references
409
- - [core/Specific](src/core/Specific.ts) - Specific object type handlers
410
- - [core/Subscript](src/core/Subscript.ts) - Subscription registry system
411
- - [index](src/index.ts) - Main exports
412
- - [wrap/AssignObject](src/wrap/AssignObject.ts) - Object assignment proxy
413
- - [wrap/Symbol](src/wrap/Symbol.ts) - Internal symbols and triggers
414
- - [wrap/Utils](src/wrap/Utils.ts) - Utility functions and types
415
-
416
- ---
417
-
418
- ## License
419
-
420
- This project is licensed under the [MIT License](LICENSE).
125
+ License: [MIT](LICENSE).
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@fest-lib/object",
3
3
  "description": "fest-lib reactivity: observe, affected, refs, computed, collection proxies",
4
- "version": "0.1.19",
4
+ "version": "0.1.20",
5
5
  "license": "MIT",
6
6
  "type": "module",
7
7
  "sideEffects": false,