@fest-lib/object 0.1.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/LICENSE +21 -0
- package/README.md +423 -0
- package/dist/object.js +1717 -0
- package/package.json +75 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 unite-2.ts
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,423 @@
|
|
|
1
|
+
# Object.TS
|
|
2
|
+
|
|
3
|
+
<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">
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/@fest-lib/object.ts)
|
|
6
|
+
[](https://github.com/fest-live/object.ts/actions)
|
|
7
|
+
[](https://codecov.io/gh/fest-live/object.ts)
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
**Object.ts** is a lightweight library providing reactive primitives and object utilities for JavaScript. It is a minor sibling of [`Uniform.TS`](https://github.com/fest-live/uniform.ts), originally created in early 2024 and partially revisited in 2025. The library is primarily used in internal projects and is designed to be compatible with modern reactive libraries.
|
|
12
|
+
|
|
13
|
+
The current version provides a comprehensive reactivity system with non-intrusive subscriptions, efficient change detection, and compatibility with modern JavaScript frameworks.
|
|
14
|
+
|
|
15
|
+
## Table of Contents
|
|
16
|
+
|
|
17
|
+
- [Features](#features)
|
|
18
|
+
- [Installation](#installation)
|
|
19
|
+
- [Usage](#usage)
|
|
20
|
+
- [API Reference](#api-reference)
|
|
21
|
+
- [Reactivity](#reactivity)
|
|
22
|
+
- [DOM Utilities](#dom-utilities)
|
|
23
|
+
- [Related Projects](#related-projects)
|
|
24
|
+
- [License](#license)
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## Features
|
|
29
|
+
|
|
30
|
+
- **Non-intrusive subscriptions:** Subscribers do not retain references to target objects.
|
|
31
|
+
- **Efficient reactivity:** Triggers only on actual value changes.
|
|
32
|
+
- **Compatibility:** Works with recent versions of popular reactive libraries.
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## Usage & Examples
|
|
37
|
+
|
|
38
|
+
### Reactivity (basics)
|
|
39
|
+
|
|
40
|
+
- **`observe(initial)`**
|
|
41
|
+
Creates a reactive primitive from an existing object, array, Set, or Map.
|
|
42
|
+
|
|
43
|
+
- **`affected(obj, callback)`**
|
|
44
|
+
Subscribes to changes in an observable object, `Set`, or `Map`.
|
|
45
|
+
- Supports `[obj, key]` to subscribe to a specific property.
|
|
46
|
+
- Returns an unsubscribe function.
|
|
47
|
+
|
|
48
|
+
- **`ref(initial)`**
|
|
49
|
+
Creates an observable reference with a `value` property.
|
|
50
|
+
|
|
51
|
+
- **`computed(src, cb, behavior, prop)`**
|
|
52
|
+
Creates a computed reactive value from a source.
|
|
53
|
+
- Computes its value using a callback function.
|
|
54
|
+
- Automatically updates when dependencies change.
|
|
55
|
+
|
|
56
|
+
- **`conditional(cond, ifTrue, ifFalse)`**
|
|
57
|
+
Reactive value that switches between `ifTrue` and `ifFalse` based on `cond.value`.
|
|
58
|
+
|
|
59
|
+
### Install
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
npm i @fest-lib/object.ts
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### Importing
|
|
66
|
+
|
|
67
|
+
```ts
|
|
68
|
+
import {
|
|
69
|
+
// Core reactivity
|
|
70
|
+
observe,
|
|
71
|
+
affected,
|
|
72
|
+
makeArrayObservable,
|
|
73
|
+
isObservable,
|
|
74
|
+
recoverReactive,
|
|
75
|
+
|
|
76
|
+
// Primitive refs
|
|
77
|
+
ref,
|
|
78
|
+
numberRef,
|
|
79
|
+
stringRef,
|
|
80
|
+
booleanRef,
|
|
81
|
+
autoRef,
|
|
82
|
+
promised,
|
|
83
|
+
|
|
84
|
+
// Computed and derived values
|
|
85
|
+
computed,
|
|
86
|
+
derivate,
|
|
87
|
+
conditional,
|
|
88
|
+
remap,
|
|
89
|
+
unified,
|
|
90
|
+
|
|
91
|
+
// Binding and assignment
|
|
92
|
+
bindBy,
|
|
93
|
+
assign,
|
|
94
|
+
link,
|
|
95
|
+
|
|
96
|
+
// Collection utilities
|
|
97
|
+
observableBySet,
|
|
98
|
+
observableByMap,
|
|
99
|
+
iterated,
|
|
100
|
+
|
|
101
|
+
// Subscription management
|
|
102
|
+
unaffected,
|
|
103
|
+
triggerWithDelay,
|
|
104
|
+
delayedBehavior,
|
|
105
|
+
delayedOrInstantBehavior,
|
|
106
|
+
|
|
107
|
+
// Utilities
|
|
108
|
+
safe,
|
|
109
|
+
deref,
|
|
110
|
+
unwrap,
|
|
111
|
+
propRef,
|
|
112
|
+
|
|
113
|
+
// Legacy (deprecated)
|
|
114
|
+
createReactive,
|
|
115
|
+
createReactiveMap,
|
|
116
|
+
createReactiveSet
|
|
117
|
+
} from "@fest-lib/object.ts";
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### Quick start
|
|
121
|
+
|
|
122
|
+
```ts
|
|
123
|
+
const state = observe({ count: 0, user: { name: "Ada" } });
|
|
124
|
+
|
|
125
|
+
const stop = affected(state, (value, prop) => {
|
|
126
|
+
console.log("changed:", prop, value[prop as keyof typeof value]);
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
state.count = 1;
|
|
130
|
+
stop?.();
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### Primitive refs
|
|
134
|
+
|
|
135
|
+
```ts
|
|
136
|
+
const n = numberRef(0);
|
|
137
|
+
const s = stringRef("hello");
|
|
138
|
+
const b = booleanRef(false);
|
|
139
|
+
|
|
140
|
+
n.value++; // 1
|
|
141
|
+
s.value = s + "!"; // "hello!"
|
|
142
|
+
b.value = 1; // true (truthy coercion)
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
#### Auto ref and promised
|
|
146
|
+
|
|
147
|
+
```ts
|
|
148
|
+
const r1 = autoRef(true); // booleanRef
|
|
149
|
+
const r2 = autoRef(42); // numberRef
|
|
150
|
+
const r3 = autoRef("hi"); // stringRef
|
|
151
|
+
const r4 = ref<any>({ a: 1 });
|
|
152
|
+
|
|
153
|
+
const later = promised(fetch("/api").then(r => r.status));
|
|
154
|
+
subscribe(later, () => console.log("ready:", later.value));
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
### Observing collections and properties
|
|
158
|
+
|
|
159
|
+
```ts
|
|
160
|
+
const list = observe([1, 2, 3]);
|
|
161
|
+
const bag = observe(new Set(["a", "b"]));
|
|
162
|
+
const map = observe(new Map([["x", 1]]));
|
|
163
|
+
|
|
164
|
+
const unAll = affected(list, (v, prop) => console.log("list changed", prop));
|
|
165
|
+
const unBag = affected(bag, (v, prop) => console.log("set changed", prop));
|
|
166
|
+
const unMap = affected(map, (v, prop) => console.log("map changed", prop));
|
|
167
|
+
|
|
168
|
+
const person = observe({ name: "Ada", age: 36 });
|
|
169
|
+
const unName = affected([person, "name"], (v) => console.log("name:", v));
|
|
170
|
+
|
|
171
|
+
person.name = "Grace";
|
|
172
|
+
unAll?.(); unBag?.(); unMap?.(); unName?.();
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
### Deriving and binding
|
|
176
|
+
|
|
177
|
+
```ts
|
|
178
|
+
const source = observe({ x: 1, y: 2 });
|
|
179
|
+
|
|
180
|
+
// Read-only derivative
|
|
181
|
+
const sum = derivate(source, s => ({ sum: s.x + s.y }));
|
|
182
|
+
affected(sum, () => console.log("sum:", sum.sum));
|
|
183
|
+
|
|
184
|
+
// Two-way bind by shape
|
|
185
|
+
const target: any = { x: 0, y: 0 };
|
|
186
|
+
bindBy(target, source);
|
|
187
|
+
|
|
188
|
+
source.x = 3; // target.x becomes 3
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
### Safe serialization
|
|
192
|
+
|
|
193
|
+
```ts
|
|
194
|
+
const complex = observe({ d: new Date(), w: new WeakRef({ a: 1 }) });
|
|
195
|
+
JSON.stringify(safe(complex));
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
### Computed values
|
|
199
|
+
|
|
200
|
+
```ts
|
|
201
|
+
const state = observe({ a: 1, b: 2 });
|
|
202
|
+
const sum = computed(state, s => s.a + s.b);
|
|
203
|
+
|
|
204
|
+
affected(sum, () => console.log("sum changed:", sum.value));
|
|
205
|
+
state.a = 3; // triggers: sum changed: 5
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
### Conditional reactivity
|
|
209
|
+
|
|
210
|
+
```ts
|
|
211
|
+
const condition = booleanRef(true);
|
|
212
|
+
const result = conditional(condition, "yes", "no");
|
|
213
|
+
|
|
214
|
+
affected(result, () => console.log("result:", result.value));
|
|
215
|
+
condition.value = false; // triggers: result: no
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
### Property references
|
|
219
|
+
|
|
220
|
+
```ts
|
|
221
|
+
const obj = observe({ nested: { value: 42 } });
|
|
222
|
+
const propRef = propRef(obj, "nested.value");
|
|
223
|
+
|
|
224
|
+
affected(propRef, () => console.log("nested value:", propRef.value));
|
|
225
|
+
obj.nested.value = 100; // triggers: nested value: 100
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
### Collection observables
|
|
229
|
+
|
|
230
|
+
```ts
|
|
231
|
+
const set = observe(new Set([1, 2, 3]));
|
|
232
|
+
const arrayFromSet = observableBySet(set);
|
|
233
|
+
|
|
234
|
+
affected(arrayFromSet, () => console.log("set as array:", arrayFromSet));
|
|
235
|
+
set.add(4); // triggers: set as array: [1, 2, 3, 4]
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
### Notes
|
|
239
|
+
|
|
240
|
+
- Subscriptions fire only on actual changes.
|
|
241
|
+
- `observe` adapts `Set`/`Map` to emit iteration changes.
|
|
242
|
+
- To stop listening, keep the disposer returned by `affected` and call it.
|
|
243
|
+
|
|
244
|
+
## API Reference
|
|
245
|
+
|
|
246
|
+
### Core Reactivity
|
|
247
|
+
|
|
248
|
+
#### `observe<T>(target: T): observeValid<T>`
|
|
249
|
+
|
|
250
|
+
Creates a reactive proxy from an object, array, Set, or Map. Changes to the reactive object will trigger subscriptions.
|
|
251
|
+
|
|
252
|
+
```ts
|
|
253
|
+
const obj = observe({ count: 0 });
|
|
254
|
+
const arr = observe([1, 2, 3]);
|
|
255
|
+
const set = observe(new Set([1, 2]));
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
#### `affected(obj, callback): UnsubscribeFn`
|
|
259
|
+
|
|
260
|
+
Subscribes to changes on a reactive object. Returns an unsubscribe function.
|
|
261
|
+
|
|
262
|
+
```ts
|
|
263
|
+
const state = observe({ count: 0 });
|
|
264
|
+
const unsubscribe = affected(state, (value, prop, old) => {
|
|
265
|
+
console.log(`${prop} changed from ${old} to ${value[prop]}`);
|
|
266
|
+
});
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
#### `isObservable(obj): boolean`
|
|
270
|
+
|
|
271
|
+
Checks if an object is already reactive.
|
|
272
|
+
|
|
273
|
+
#### `recoverReactive(obj): observeValid | null`
|
|
274
|
+
|
|
275
|
+
Attempts to recover the reactive version of an object.
|
|
276
|
+
|
|
277
|
+
### Reactive References
|
|
278
|
+
|
|
279
|
+
#### `ref<T>(initial: T): Ref<T>`
|
|
280
|
+
|
|
281
|
+
Creates a reactive reference with a `.value` property.
|
|
282
|
+
|
|
283
|
+
#### `numberRef(initial?: number): NumberRef`
|
|
284
|
+
|
|
285
|
+
Creates a reactive number reference with type coercion.
|
|
286
|
+
|
|
287
|
+
#### `stringRef(initial?: string): StringRef`
|
|
288
|
+
|
|
289
|
+
Creates a reactive string reference with type coercion.
|
|
290
|
+
|
|
291
|
+
#### `booleanRef(initial?: boolean): BooleanRef`
|
|
292
|
+
|
|
293
|
+
Creates a reactive boolean reference with truthy coercion.
|
|
294
|
+
|
|
295
|
+
#### `autoRef(initial: any): Ref`
|
|
296
|
+
|
|
297
|
+
Automatically creates the appropriate ref type based on the initial value.
|
|
298
|
+
|
|
299
|
+
#### `promised<T>(promise: Promise<T>): PromisedRef<T>`
|
|
300
|
+
|
|
301
|
+
Creates a reactive reference from a Promise.
|
|
302
|
+
|
|
303
|
+
### Computed Values
|
|
304
|
+
|
|
305
|
+
#### `computed<T>(src, cb, behavior?, prop?): ComputedRef<T>`
|
|
306
|
+
|
|
307
|
+
Creates a computed reactive value that updates when its dependencies change.
|
|
308
|
+
|
|
309
|
+
```ts
|
|
310
|
+
const state = observe({ a: 1, b: 2 });
|
|
311
|
+
const sum = computed(state, s => s.a + s.b);
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
#### `derivate<T>(from, reactFn, watch?): observeValid`
|
|
315
|
+
|
|
316
|
+
Creates a derived reactive object from a source.
|
|
317
|
+
|
|
318
|
+
#### `conditional<T>(cond, ifTrue, ifFalse): ConditionalRef<T>`
|
|
319
|
+
|
|
320
|
+
Creates a reactive value that switches between two values based on a condition.
|
|
321
|
+
|
|
322
|
+
### Binding & Assignment
|
|
323
|
+
|
|
324
|
+
#### `bindBy(target, reactive, watch?)`
|
|
325
|
+
|
|
326
|
+
Two-way binds a target object to a reactive source.
|
|
327
|
+
|
|
328
|
+
#### `assign<T>(a, b, prop?): UnsubscribeFn`
|
|
329
|
+
|
|
330
|
+
Assigns reactive values between objects with automatic synchronization.
|
|
331
|
+
|
|
332
|
+
#### `link<T>(a, b, prop?): UnsubscribeFn`
|
|
333
|
+
|
|
334
|
+
Creates a bidirectional link between two reactive values.
|
|
335
|
+
|
|
336
|
+
### Collection Utilities
|
|
337
|
+
|
|
338
|
+
#### `observableBySet<T>(set: Set<T>): T[]`
|
|
339
|
+
|
|
340
|
+
Converts a reactive Set to a reactive array.
|
|
341
|
+
|
|
342
|
+
#### `observableByMap<K, V>(map: Map<K, V>): [K, V][]`
|
|
343
|
+
|
|
344
|
+
Converts a reactive Map to a reactive array of key-value pairs.
|
|
345
|
+
|
|
346
|
+
#### `iterated<T>(target, cb, ctx?): UnsubscribeFn`
|
|
347
|
+
|
|
348
|
+
Subscribes to iteration changes on collections.
|
|
349
|
+
|
|
350
|
+
#### `makeArrayObservable(target): observeValid`
|
|
351
|
+
|
|
352
|
+
Makes arrays observable.
|
|
353
|
+
|
|
354
|
+
### Utilities
|
|
355
|
+
|
|
356
|
+
#### `safe(obj): any`
|
|
357
|
+
|
|
358
|
+
Prepares an object for JSON serialization by handling circular references and WeakRefs.
|
|
359
|
+
|
|
360
|
+
#### `deref(obj): any`
|
|
361
|
+
|
|
362
|
+
Dereferences WeakRefs and unwraps reactive objects.
|
|
363
|
+
|
|
364
|
+
#### `unwrap(obj): any`
|
|
365
|
+
|
|
366
|
+
Unwraps reactive objects to their original form.
|
|
367
|
+
|
|
368
|
+
#### `propRef<T>(src, prop, initial?, behavior?): Ref<T>`
|
|
369
|
+
|
|
370
|
+
Creates a reactive reference to a specific property.
|
|
371
|
+
|
|
372
|
+
### Subscription Management
|
|
373
|
+
|
|
374
|
+
#### `unaffected<T>(target, cb?, ctx?): Promise<T>`
|
|
375
|
+
|
|
376
|
+
Removes subscriptions from an object.
|
|
377
|
+
|
|
378
|
+
#### `triggerWithDelay(ref, cb, delay?): Timeout`
|
|
379
|
+
|
|
380
|
+
Triggers a callback after a delay if the ref value is truthy.
|
|
381
|
+
|
|
382
|
+
#### `delayedBehavior(delay?): Function`
|
|
383
|
+
|
|
384
|
+
Creates a behavior function that delays execution.
|
|
385
|
+
|
|
386
|
+
#### `delayedOrInstantBehavior(delay?): Function`
|
|
387
|
+
|
|
388
|
+
Creates a behavior that executes immediately or after delay.
|
|
389
|
+
|
|
390
|
+
### Legacy (Deprecated)
|
|
391
|
+
|
|
392
|
+
#### `createReactive(target, stateName?)`
|
|
393
|
+
|
|
394
|
+
Legacy function for creating reactive objects.
|
|
395
|
+
|
|
396
|
+
#### `createReactiveMap<K, V>(map?): Map<K, V>`
|
|
397
|
+
|
|
398
|
+
Legacy function for creating reactive Maps.
|
|
399
|
+
|
|
400
|
+
#### `createReactiveSet<V>(set?): Set<V>`
|
|
401
|
+
|
|
402
|
+
Legacy function for creating reactive Sets.
|
|
403
|
+
|
|
404
|
+
***
|
|
405
|
+
|
|
406
|
+
## Modules
|
|
407
|
+
|
|
408
|
+
- [core/Assigned](docs/core/Assigned/README.md) - Assignment and binding utilities
|
|
409
|
+
- [core/Legacy](docs/core/Legacy/README.md) - Legacy compatibility functions
|
|
410
|
+
- [core/Mainline](docs/core/Mainline/README.md) - Core subscription and reactivity system
|
|
411
|
+
- [core/Primitives](docs/core/Primitives/README.md) - Primitive reactive references
|
|
412
|
+
- [core/Specific](docs/core/Specific/README.md) - Specific object type handlers
|
|
413
|
+
- [core/Subscript](docs/core/Subscript/README.md) - Subscription registry system
|
|
414
|
+
- [index](docs/index/README.md) - Main exports
|
|
415
|
+
- [wrap/AssignObject](docs/wrap/AssignObject/README.md) - Object assignment proxy
|
|
416
|
+
- [wrap/Symbol](docs/wrap/Symbol/README.md) - Internal symbols and triggers
|
|
417
|
+
- [wrap/Utils](docs/wrap/Utils/README.md) - Utility functions and types
|
|
418
|
+
|
|
419
|
+
---
|
|
420
|
+
|
|
421
|
+
## License
|
|
422
|
+
|
|
423
|
+
This project is licensed under the [MIT License](LICENSE).
|