@rlabs-inc/signals 1.4.1 → 1.4.3
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 +353 -229
- package/dist/core/types.d.ts +14 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/primitives/bind.d.ts +2 -2
- package/dist/primitives/bind.d.ts.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,23 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
**Production-grade fine-grained reactivity for TypeScript.**
|
|
4
4
|
|
|
5
|
-
A complete standalone mirror of Svelte 5's reactivity system. No compiler needed, no DOM, works anywhere - Bun, Node, Deno, or browser.
|
|
5
|
+
A complete standalone mirror of Svelte 5's reactivity system, enhanced with Angular's linkedSignal, Solid's createSelector, and Vue's effectScope. No compiler needed, no DOM, works anywhere - Bun, Node, Deno, or browser.
|
|
6
6
|
|
|
7
|
-
##
|
|
7
|
+
## Why This Library?
|
|
8
8
|
|
|
9
9
|
- **True Fine-Grained Reactivity** - Changes to deeply nested properties only trigger effects that read that exact path
|
|
10
10
|
- **Per-Property Tracking** - Proxy-based deep reactivity with lazy signal creation per property
|
|
11
|
-
- **
|
|
12
|
-
- **
|
|
13
|
-
- **
|
|
14
|
-
- **
|
|
15
|
-
- **Three-State Dirty Tracking** - Efficient CLEAN/MAYBE_DIRTY/DIRTY propagation
|
|
16
|
-
- **Automatic Cleanup** - Effects clean up when disposed, no memory leaks
|
|
17
|
-
- **Batching** - Group updates to prevent redundant effect runs
|
|
18
|
-
- **Self-Referencing Effects** - Effects can write to their own dependencies
|
|
19
|
-
- **Infinite Loop Protection** - Throws after 1000 iterations to catch bugs
|
|
20
|
-
- **Reactive Collections** - ReactiveMap, ReactiveSet, ReactiveDate
|
|
21
|
-
- **TypeScript Native** - Full type safety with generics
|
|
11
|
+
- **Framework-Agnostic** - Use the best patterns from Svelte, Angular, Solid, and Vue in any environment
|
|
12
|
+
- **Zero Dependencies** - Pure TypeScript, no runtime dependencies
|
|
13
|
+
- **Automatic Memory Cleanup** - FinalizationRegistry ensures signals are garbage collected properly
|
|
14
|
+
- **Battle-Tested Patterns** - Based on proven reactivity systems from major frameworks
|
|
22
15
|
|
|
23
16
|
## Installation
|
|
24
17
|
|
|
@@ -52,39 +45,88 @@ count.value = 5
|
|
|
52
45
|
flushSync() // Logs: "Count: 5, Doubled: 10"
|
|
53
46
|
```
|
|
54
47
|
|
|
55
|
-
|
|
48
|
+
---
|
|
56
49
|
|
|
57
|
-
|
|
50
|
+
## Core Primitives
|
|
58
51
|
|
|
59
|
-
|
|
52
|
+
### signal
|
|
60
53
|
|
|
61
54
|
Create a reactive value with `.value` getter/setter.
|
|
62
55
|
|
|
56
|
+
```typescript
|
|
57
|
+
signal<T>(initialValue: T, options?: { equals?: (a: T, b: T) => boolean }): WritableSignal<T>
|
|
58
|
+
```
|
|
59
|
+
|
|
63
60
|
```typescript
|
|
64
61
|
const name = signal('John')
|
|
65
62
|
console.log(name.value) // 'John'
|
|
66
63
|
name.value = 'Jane' // Triggers effects
|
|
67
64
|
```
|
|
68
65
|
|
|
69
|
-
|
|
70
|
-
- `equals?: (a: T, b: T) => boolean` - Custom equality function
|
|
66
|
+
### signals
|
|
71
67
|
|
|
72
|
-
|
|
68
|
+
Create multiple signals at once from an object.
|
|
69
|
+
|
|
70
|
+
```typescript
|
|
71
|
+
signals<T>(initial: T): { [K in keyof T]: WritableSignal<T[K]> }
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
```typescript
|
|
75
|
+
// Instead of:
|
|
76
|
+
const content = signal('hello')
|
|
77
|
+
const width = signal(40)
|
|
78
|
+
const visible = signal(true)
|
|
79
|
+
|
|
80
|
+
// Do this:
|
|
81
|
+
const ui = signals({ content: 'hello', width: 40, visible: true })
|
|
82
|
+
ui.content.value = 'updated'
|
|
83
|
+
ui.width.value = 60
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### state
|
|
73
87
|
|
|
74
88
|
Create a deeply reactive object. No `.value` needed - access properties directly.
|
|
75
89
|
|
|
76
90
|
```typescript
|
|
77
|
-
|
|
91
|
+
state<T extends object>(initialValue: T): T
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
```typescript
|
|
95
|
+
const user = state({
|
|
96
|
+
name: 'John',
|
|
97
|
+
address: { city: 'NYC' }
|
|
98
|
+
})
|
|
78
99
|
user.name = 'Jane' // Reactive
|
|
79
100
|
user.address.city = 'LA' // Also reactive, deeply
|
|
80
101
|
```
|
|
81
102
|
|
|
82
|
-
###
|
|
103
|
+
### stateRaw
|
|
83
104
|
|
|
84
|
-
|
|
105
|
+
Create a signal that holds an object reference without deep reactivity. Only triggers when the reference changes, not on mutations.
|
|
106
|
+
|
|
107
|
+
```typescript
|
|
108
|
+
stateRaw<T>(initialValue: T): WritableSignal<T>
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
```typescript
|
|
112
|
+
const canvas = stateRaw(document.createElement('canvas'))
|
|
113
|
+
// Only triggers when canvas.value is reassigned
|
|
114
|
+
// Mutations to the canvas element don't trigger effects
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
Use `stateRaw` for:
|
|
118
|
+
- DOM elements
|
|
119
|
+
- Class instances
|
|
120
|
+
- Large objects where you only care about replacement
|
|
121
|
+
|
|
122
|
+
### derived
|
|
85
123
|
|
|
86
124
|
Create a computed value that automatically updates when dependencies change.
|
|
87
125
|
|
|
126
|
+
```typescript
|
|
127
|
+
derived<T>(fn: () => T, options?: { equals?: Equals<T> }): DerivedSignal<T>
|
|
128
|
+
```
|
|
129
|
+
|
|
88
130
|
```typescript
|
|
89
131
|
const firstName = signal('John')
|
|
90
132
|
const lastName = signal('Doe')
|
|
@@ -98,132 +140,143 @@ Deriveds are:
|
|
|
98
140
|
- **Cached** - Value is memoized until dependencies change
|
|
99
141
|
- **Pure** - Cannot write to signals inside (throws error)
|
|
100
142
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
#### `bind<T>(source: WritableSignal<T>): Binding<T>`
|
|
143
|
+
---
|
|
104
144
|
|
|
105
|
-
|
|
145
|
+
## Effects
|
|
106
146
|
|
|
107
|
-
|
|
108
|
-
const source = signal(0)
|
|
109
|
-
const binding = bind(source)
|
|
147
|
+
### effect
|
|
110
148
|
|
|
111
|
-
|
|
112
|
-
console.log(binding.value) // 0
|
|
149
|
+
Create a side effect that re-runs when dependencies change.
|
|
113
150
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
console.log(source.value) // 42
|
|
151
|
+
```typescript
|
|
152
|
+
effect(fn: () => void | CleanupFn): DisposeFn
|
|
117
153
|
```
|
|
118
154
|
|
|
119
|
-
**Use cases:**
|
|
120
|
-
- Two-way binding for form inputs
|
|
121
|
-
- Connecting parent state to child components
|
|
122
|
-
- Creating reactive links between signals
|
|
123
|
-
|
|
124
155
|
```typescript
|
|
125
|
-
|
|
126
|
-
const username = signal('')
|
|
127
|
-
const inputBinding = bind(username)
|
|
156
|
+
const count = signal(0)
|
|
128
157
|
|
|
129
|
-
|
|
130
|
-
|
|
158
|
+
const dispose = effect(() => {
|
|
159
|
+
console.log('Count is:', count.value)
|
|
131
160
|
|
|
132
|
-
//
|
|
133
|
-
|
|
161
|
+
// Optional cleanup function
|
|
162
|
+
return () => {
|
|
163
|
+
console.log('Cleaning up...')
|
|
164
|
+
}
|
|
165
|
+
})
|
|
166
|
+
|
|
167
|
+
// Stop the effect
|
|
168
|
+
dispose()
|
|
134
169
|
```
|
|
135
170
|
|
|
136
|
-
|
|
171
|
+
### effect.pre
|
|
137
172
|
|
|
138
|
-
Create
|
|
173
|
+
Create an effect that runs synchronously (like `$effect.pre` in Svelte).
|
|
139
174
|
|
|
140
175
|
```typescript
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
console.log(readonly.value) // 0
|
|
145
|
-
// readonly.value = 42 // Would throw at compile time
|
|
176
|
+
effect.pre(() => {
|
|
177
|
+
// Runs immediately, not on microtask
|
|
178
|
+
})
|
|
146
179
|
```
|
|
147
180
|
|
|
148
|
-
|
|
181
|
+
### effect.root
|
|
149
182
|
|
|
150
|
-
|
|
183
|
+
Create an effect scope that can contain nested effects.
|
|
151
184
|
|
|
152
185
|
```typescript
|
|
153
|
-
const
|
|
154
|
-
|
|
155
|
-
|
|
186
|
+
const dispose = effect.root(() => {
|
|
187
|
+
effect(() => { /* ... */ })
|
|
188
|
+
effect(() => { /* ... */ })
|
|
189
|
+
})
|
|
190
|
+
|
|
191
|
+
// Disposes all nested effects
|
|
192
|
+
dispose()
|
|
156
193
|
```
|
|
157
194
|
|
|
158
|
-
|
|
195
|
+
### effect.tracking
|
|
159
196
|
|
|
160
|
-
|
|
197
|
+
Check if currently inside a reactive tracking context.
|
|
161
198
|
|
|
162
199
|
```typescript
|
|
163
|
-
|
|
164
|
-
'
|
|
165
|
-
|
|
166
|
-
]
|
|
167
|
-
|
|
168
|
-
arr.map(unwrap) // ['static', 'dynamic']
|
|
200
|
+
if (effect.tracking()) {
|
|
201
|
+
console.log('Inside an effect or derived')
|
|
202
|
+
}
|
|
169
203
|
```
|
|
170
204
|
|
|
171
|
-
|
|
205
|
+
---
|
|
172
206
|
|
|
173
|
-
|
|
207
|
+
## Bindings
|
|
174
208
|
|
|
175
|
-
|
|
209
|
+
Two-way reactive pointers that forward reads and writes to a source signal.
|
|
210
|
+
|
|
211
|
+
### bind
|
|
212
|
+
|
|
213
|
+
Create a reactive binding.
|
|
176
214
|
|
|
177
215
|
```typescript
|
|
178
|
-
|
|
216
|
+
bind<T>(source: WritableSignal<T> | Binding<T> | T | (() => T)): Binding<T>
|
|
217
|
+
```
|
|
179
218
|
|
|
180
|
-
|
|
181
|
-
|
|
219
|
+
```typescript
|
|
220
|
+
const source = signal(0)
|
|
221
|
+
const binding = bind(source)
|
|
182
222
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
console.log('Cleaning up...')
|
|
186
|
-
}
|
|
187
|
-
})
|
|
223
|
+
// Reading through binding reads from source
|
|
224
|
+
console.log(binding.value) // 0
|
|
188
225
|
|
|
189
|
-
//
|
|
190
|
-
|
|
226
|
+
// Writing through binding writes to source
|
|
227
|
+
binding.value = 42
|
|
228
|
+
console.log(source.value) // 42
|
|
191
229
|
```
|
|
192
230
|
|
|
193
|
-
|
|
231
|
+
**Overloads:**
|
|
232
|
+
- `bind(signal)` - Creates writable binding to signal
|
|
233
|
+
- `bind(binding)` - Chains bindings (both point to same source)
|
|
234
|
+
- `bind(value)` - Wraps raw value in a signal
|
|
235
|
+
- `bind(() => expr)` - Creates read-only binding from getter
|
|
194
236
|
|
|
195
|
-
|
|
237
|
+
**Use cases:**
|
|
238
|
+
- Two-way binding for form inputs
|
|
239
|
+
- Connecting parent state to child components
|
|
240
|
+
- Creating reactive links between signals
|
|
241
|
+
|
|
242
|
+
### bindReadonly
|
|
243
|
+
|
|
244
|
+
Create a read-only binding.
|
|
196
245
|
|
|
197
246
|
```typescript
|
|
198
|
-
const
|
|
199
|
-
|
|
200
|
-
effect(() => { /* ... */ })
|
|
201
|
-
})
|
|
247
|
+
const source = signal(0)
|
|
248
|
+
const readonly = bindReadonly(source)
|
|
202
249
|
|
|
203
|
-
//
|
|
204
|
-
|
|
250
|
+
console.log(readonly.value) // 0
|
|
251
|
+
// readonly.value = 42 // TypeScript error + runtime error
|
|
205
252
|
```
|
|
206
253
|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
Create an effect that runs synchronously (like `$effect.pre` in Svelte).
|
|
254
|
+
### isBinding / unwrap
|
|
210
255
|
|
|
211
256
|
```typescript
|
|
212
|
-
|
|
213
|
-
//
|
|
214
|
-
|
|
257
|
+
// Check if a value is a binding
|
|
258
|
+
isBinding(maybeBinding) // true or false
|
|
259
|
+
|
|
260
|
+
// Get value from binding or return value directly
|
|
261
|
+
const arr: (string | Binding<string>)[] = ['static', bind(signal('dynamic'))]
|
|
262
|
+
arr.map(unwrap) // ['static', 'dynamic']
|
|
215
263
|
```
|
|
216
264
|
|
|
217
|
-
|
|
265
|
+
---
|
|
218
266
|
|
|
219
|
-
|
|
220
|
-
#### `linkedSignal<S, D>(options: LinkedSignalOptions<S, D>): WritableSignal<D>`
|
|
267
|
+
## Advanced Features
|
|
221
268
|
|
|
222
|
-
|
|
223
|
-
|
|
269
|
+
### linkedSignal (Angular's killer feature)
|
|
270
|
+
|
|
271
|
+
Create a writable signal that derives from a source but can be manually overridden. When the source changes, the linked signal resets to the computed value.
|
|
224
272
|
|
|
225
273
|
```typescript
|
|
226
|
-
|
|
274
|
+
linkedSignal<D>(fn: () => D): WritableSignal<D>
|
|
275
|
+
linkedSignal<S, D>(options: LinkedSignalOptions<S, D>): WritableSignal<D>
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
```typescript
|
|
279
|
+
// Simple form - dropdown selection
|
|
227
280
|
const options = signal(['a', 'b', 'c'])
|
|
228
281
|
const selected = linkedSignal(() => options.value[0])
|
|
229
282
|
|
|
@@ -237,7 +290,7 @@ console.log(selected.value) // 'x' (reset to computed value)
|
|
|
237
290
|
```
|
|
238
291
|
|
|
239
292
|
```typescript
|
|
240
|
-
// Advanced form -
|
|
293
|
+
// Advanced form - keep valid selection
|
|
241
294
|
const items = signal([1, 2, 3])
|
|
242
295
|
const selectedItem = linkedSignal({
|
|
243
296
|
source: () => items.value,
|
|
@@ -256,12 +309,16 @@ const selectedItem = linkedSignal({
|
|
|
256
309
|
- Selection state that persists within valid options
|
|
257
310
|
- Derived values that can be temporarily overridden
|
|
258
311
|
|
|
259
|
-
###
|
|
312
|
+
### createSelector (Solid's O(n) to O(2) optimization)
|
|
260
313
|
|
|
261
|
-
|
|
314
|
+
Create a selector function for efficient list selection tracking. Instead of O(n) effects re-running, only affected items run = O(2).
|
|
262
315
|
|
|
263
|
-
|
|
264
|
-
|
|
316
|
+
```typescript
|
|
317
|
+
createSelector<T, U = T>(
|
|
318
|
+
source: () => T,
|
|
319
|
+
fn?: (key: U, value: T) => boolean
|
|
320
|
+
): SelectorFn<T, U>
|
|
321
|
+
```
|
|
265
322
|
|
|
266
323
|
```typescript
|
|
267
324
|
const selectedId = signal(1)
|
|
@@ -284,17 +341,27 @@ items.forEach(item => {
|
|
|
284
341
|
})
|
|
285
342
|
```
|
|
286
343
|
|
|
287
|
-
###
|
|
288
|
-
|
|
289
|
-
#### `effectScope(detached?: boolean): EffectScope`
|
|
344
|
+
### effectScope (Vue's lifecycle management)
|
|
290
345
|
|
|
291
346
|
Create an effect scope to group effects for batch disposal with pause/resume support.
|
|
292
347
|
|
|
348
|
+
```typescript
|
|
349
|
+
effectScope(detached?: boolean): EffectScope
|
|
350
|
+
|
|
351
|
+
interface EffectScope {
|
|
352
|
+
readonly active: boolean
|
|
353
|
+
readonly paused: boolean
|
|
354
|
+
run<R>(fn: () => R): R | undefined
|
|
355
|
+
stop(): void
|
|
356
|
+
pause(): void
|
|
357
|
+
resume(): void
|
|
358
|
+
}
|
|
359
|
+
```
|
|
360
|
+
|
|
293
361
|
```typescript
|
|
294
362
|
const scope = effectScope()
|
|
295
363
|
|
|
296
364
|
scope.run(() => {
|
|
297
|
-
// Effects created here are tracked by the scope
|
|
298
365
|
effect(() => console.log(count.value))
|
|
299
366
|
effect(() => console.log(name.value))
|
|
300
367
|
|
|
@@ -303,198 +370,211 @@ scope.run(() => {
|
|
|
303
370
|
})
|
|
304
371
|
})
|
|
305
372
|
|
|
373
|
+
// Pause execution temporarily
|
|
374
|
+
scope.pause()
|
|
375
|
+
count.value = 5 // Effect doesn't run
|
|
376
|
+
|
|
377
|
+
// Resume and run pending updates
|
|
378
|
+
scope.resume()
|
|
379
|
+
|
|
306
380
|
// Later, dispose all effects at once
|
|
307
381
|
scope.stop()
|
|
308
382
|
```
|
|
309
383
|
|
|
310
|
-
|
|
384
|
+
### onScopeDispose
|
|
311
385
|
|
|
312
|
-
|
|
313
|
-
scope.pause() // Effects won't run while paused
|
|
314
|
-
|
|
315
|
-
count.value = 5 // Effect doesn't run
|
|
386
|
+
Register a cleanup function on the current scope.
|
|
316
387
|
|
|
317
|
-
|
|
388
|
+
```typescript
|
|
389
|
+
scope.run(() => {
|
|
390
|
+
const timer = setInterval(() => log('tick'), 1000)
|
|
391
|
+
onScopeDispose(() => clearInterval(timer))
|
|
392
|
+
})
|
|
318
393
|
```
|
|
319
394
|
|
|
320
|
-
|
|
395
|
+
### getCurrentScope
|
|
321
396
|
|
|
322
397
|
Get the currently active effect scope.
|
|
323
398
|
|
|
324
|
-
|
|
399
|
+
```typescript
|
|
400
|
+
const scope = getCurrentScope()
|
|
401
|
+
if (scope) {
|
|
402
|
+
// Inside a scope
|
|
403
|
+
}
|
|
404
|
+
```
|
|
325
405
|
|
|
326
|
-
|
|
406
|
+
---
|
|
327
407
|
|
|
328
|
-
|
|
408
|
+
## Reactive Collections
|
|
329
409
|
|
|
330
|
-
|
|
410
|
+
### ReactiveMap
|
|
331
411
|
|
|
332
|
-
|
|
412
|
+
A Map with per-key reactivity.
|
|
333
413
|
|
|
334
414
|
```typescript
|
|
335
|
-
const
|
|
336
|
-
const b = signal(2)
|
|
337
|
-
|
|
338
|
-
effect(() => console.log(a.value + b.value))
|
|
415
|
+
const users = new ReactiveMap<string, User>()
|
|
339
416
|
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
b.value = 20
|
|
417
|
+
effect(() => {
|
|
418
|
+
console.log(users.get('john')) // Only re-runs when 'john' changes
|
|
343
419
|
})
|
|
344
|
-
|
|
420
|
+
|
|
421
|
+
users.set('jane', { name: 'Jane' }) // Doesn't trigger above effect
|
|
422
|
+
users.set('john', { name: 'John!' }) // Triggers above effect
|
|
345
423
|
```
|
|
346
424
|
|
|
347
|
-
|
|
425
|
+
### ReactiveSet
|
|
348
426
|
|
|
349
|
-
|
|
427
|
+
A Set with per-item reactivity.
|
|
350
428
|
|
|
351
429
|
```typescript
|
|
352
|
-
|
|
353
|
-
flushSync() // Effects run NOW, not on next microtask
|
|
354
|
-
```
|
|
355
|
-
|
|
356
|
-
#### `tick(): Promise<void>`
|
|
430
|
+
const tags = new ReactiveSet<string>()
|
|
357
431
|
|
|
358
|
-
|
|
432
|
+
effect(() => {
|
|
433
|
+
console.log(tags.has('important')) // Only re-runs when 'important' changes
|
|
434
|
+
})
|
|
359
435
|
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
await tick() // Effects have run
|
|
436
|
+
tags.add('todo') // Doesn't trigger above effect
|
|
437
|
+
tags.add('important') // Triggers above effect
|
|
363
438
|
```
|
|
364
439
|
|
|
365
|
-
###
|
|
366
|
-
|
|
367
|
-
#### `untrack<T>(fn: () => T): T`
|
|
440
|
+
### ReactiveDate
|
|
368
441
|
|
|
369
|
-
|
|
442
|
+
A Date with reactive getters/setters.
|
|
370
443
|
|
|
371
444
|
```typescript
|
|
445
|
+
const date = new ReactiveDate()
|
|
446
|
+
|
|
372
447
|
effect(() => {
|
|
373
|
-
|
|
374
|
-
const b = untrack(() => other.value) // No dependency
|
|
448
|
+
console.log(date.getHours()) // Re-runs when time changes
|
|
375
449
|
})
|
|
376
|
-
```
|
|
377
450
|
|
|
378
|
-
|
|
451
|
+
date.setHours(12) // Triggers effect
|
|
452
|
+
```
|
|
379
453
|
|
|
380
|
-
|
|
454
|
+
---
|
|
381
455
|
|
|
382
|
-
|
|
456
|
+
## Utilities
|
|
383
457
|
|
|
384
|
-
|
|
458
|
+
### batch
|
|
385
459
|
|
|
386
|
-
|
|
460
|
+
Batch multiple signal updates into a single effect run.
|
|
387
461
|
|
|
388
462
|
```typescript
|
|
389
|
-
const
|
|
390
|
-
|
|
391
|
-
```
|
|
392
|
-
|
|
393
|
-
#### `toRaw<T>(value: T): T`
|
|
463
|
+
const a = signal(1)
|
|
464
|
+
const b = signal(2)
|
|
394
465
|
|
|
395
|
-
|
|
466
|
+
effect(() => console.log(a.value + b.value))
|
|
396
467
|
|
|
397
|
-
|
|
398
|
-
|
|
468
|
+
batch(() => {
|
|
469
|
+
a.value = 10
|
|
470
|
+
b.value = 20
|
|
471
|
+
})
|
|
472
|
+
// Effect runs once with final values, not twice
|
|
399
473
|
```
|
|
400
474
|
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
Check if a value is a reactive proxy.
|
|
404
|
-
|
|
405
|
-
### Reactive Collections
|
|
475
|
+
### untrack / peek
|
|
406
476
|
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
A Map with per-key reactivity.
|
|
477
|
+
Read signals without creating dependencies.
|
|
410
478
|
|
|
411
479
|
```typescript
|
|
412
|
-
const users = new ReactiveMap<string, User>()
|
|
413
|
-
|
|
414
480
|
effect(() => {
|
|
415
|
-
|
|
481
|
+
const a = count.value // Creates dependency
|
|
482
|
+
const b = untrack(() => other.value) // No dependency
|
|
416
483
|
})
|
|
417
484
|
|
|
418
|
-
|
|
485
|
+
// peek is an alias for untrack
|
|
486
|
+
const value = peek(() => signal.value)
|
|
419
487
|
```
|
|
420
488
|
|
|
421
|
-
|
|
489
|
+
### flushSync
|
|
422
490
|
|
|
423
|
-
|
|
491
|
+
Synchronously flush all pending effects.
|
|
424
492
|
|
|
425
493
|
```typescript
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
effect(() => {
|
|
429
|
-
console.log(tags.has('important')) // Only re-runs when 'important' changes
|
|
430
|
-
})
|
|
494
|
+
count.value = 5
|
|
495
|
+
flushSync() // Effects run NOW, not on next microtask
|
|
431
496
|
```
|
|
432
497
|
|
|
433
|
-
|
|
498
|
+
### tick
|
|
434
499
|
|
|
435
|
-
|
|
500
|
+
Wait for the next update cycle (async).
|
|
436
501
|
|
|
437
502
|
```typescript
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
effect(() => {
|
|
441
|
-
console.log(date.getHours()) // Re-runs when time changes
|
|
442
|
-
})
|
|
443
|
-
|
|
444
|
-
date.setHours(12) // Triggers effect
|
|
503
|
+
count.value = 5
|
|
504
|
+
await tick() // Effects have run
|
|
445
505
|
```
|
|
446
506
|
|
|
447
|
-
|
|
507
|
+
---
|
|
508
|
+
|
|
509
|
+
## Deep Reactivity
|
|
448
510
|
|
|
449
|
-
###
|
|
511
|
+
### proxy
|
|
450
512
|
|
|
451
|
-
|
|
513
|
+
Create a deeply reactive proxy (used internally by `state()`).
|
|
452
514
|
|
|
453
515
|
```typescript
|
|
454
|
-
const
|
|
516
|
+
const obj = proxy({ a: { b: { c: 1 } } })
|
|
455
517
|
|
|
456
|
-
effect(() =>
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
})
|
|
518
|
+
effect(() => console.log('c changed:', obj.a.b.c))
|
|
519
|
+
effect(() => console.log('a changed:', obj.a))
|
|
520
|
+
|
|
521
|
+
obj.a.b.c = 2 // Only triggers first effect (fine-grained!)
|
|
461
522
|
```
|
|
462
523
|
|
|
463
|
-
|
|
524
|
+
### toRaw
|
|
464
525
|
|
|
465
|
-
|
|
526
|
+
Get the original object from a proxy.
|
|
466
527
|
|
|
467
528
|
```typescript
|
|
468
|
-
|
|
529
|
+
const raw = toRaw(user) // Original non-reactive object
|
|
530
|
+
```
|
|
469
531
|
|
|
470
|
-
|
|
471
|
-
|
|
532
|
+
### isReactive
|
|
533
|
+
|
|
534
|
+
Check if a value is a reactive proxy.
|
|
535
|
+
|
|
536
|
+
```typescript
|
|
537
|
+
if (isReactive(value)) {
|
|
538
|
+
console.log('This is a proxy')
|
|
539
|
+
}
|
|
472
540
|
```
|
|
473
541
|
|
|
474
|
-
|
|
475
|
-
- `equals` - Default, uses `Object.is`
|
|
476
|
-
- `safeEquals` - Handles NaN correctly
|
|
477
|
-
- `shallowEquals` - Shallow object comparison
|
|
478
|
-
- `neverEquals` - Always triggers (always false)
|
|
479
|
-
- `alwaysEquals` - Never triggers (always true)
|
|
542
|
+
---
|
|
480
543
|
|
|
481
|
-
|
|
544
|
+
## Equality Functions
|
|
482
545
|
|
|
483
|
-
|
|
546
|
+
Control when signals trigger updates:
|
|
484
547
|
|
|
485
548
|
```typescript
|
|
486
|
-
import {
|
|
549
|
+
import { signal, equals, safeEquals, shallowEquals, neverEquals, alwaysEquals, createEquals } from '@rlabs-inc/signals'
|
|
487
550
|
|
|
488
|
-
//
|
|
489
|
-
const
|
|
551
|
+
// Default - uses Object.is
|
|
552
|
+
const a = signal(0) // Uses equals by default
|
|
490
553
|
|
|
491
|
-
//
|
|
492
|
-
const
|
|
554
|
+
// Safe equality - handles NaN correctly
|
|
555
|
+
const b = signal(NaN, { equals: safeEquals })
|
|
493
556
|
|
|
494
|
-
//
|
|
495
|
-
|
|
557
|
+
// Shallow comparison - compares one level deep
|
|
558
|
+
const c = signal({ a: 1 }, { equals: shallowEquals })
|
|
559
|
+
c.value = { a: 1 } // Won't trigger - shallowly equal
|
|
560
|
+
|
|
561
|
+
// Always trigger updates
|
|
562
|
+
const d = signal(0, { equals: neverEquals })
|
|
563
|
+
d.value = 0 // Still triggers!
|
|
564
|
+
|
|
565
|
+
// Never trigger updates
|
|
566
|
+
const e = signal(0, { equals: alwaysEquals })
|
|
567
|
+
e.value = 100 // Doesn't trigger
|
|
568
|
+
|
|
569
|
+
// Custom equality
|
|
570
|
+
const customEquals = createEquals((a, b) =>
|
|
571
|
+
JSON.stringify(a) === JSON.stringify(b)
|
|
572
|
+
)
|
|
573
|
+
const f = signal([], { equals: customEquals })
|
|
496
574
|
```
|
|
497
575
|
|
|
576
|
+
---
|
|
577
|
+
|
|
498
578
|
## Error Handling
|
|
499
579
|
|
|
500
580
|
### "Cannot write to signals inside a derived"
|
|
@@ -534,29 +614,73 @@ effect(() => {
|
|
|
534
614
|
})
|
|
535
615
|
```
|
|
536
616
|
|
|
617
|
+
---
|
|
618
|
+
|
|
537
619
|
## Performance
|
|
538
620
|
|
|
539
621
|
This library is designed for performance:
|
|
540
622
|
|
|
623
|
+
| Operation | Complexity | Notes |
|
|
624
|
+
|-----------|------------|-------|
|
|
625
|
+
| Signal read/write | O(1) | Direct property access |
|
|
626
|
+
| Derived read | O(1) | Cached after first computation |
|
|
627
|
+
| Effect trigger | O(deps) | Only runs if dependencies change |
|
|
628
|
+
| `batch()` | O(1) cycle | Multiple updates, single flush |
|
|
629
|
+
| `createSelector()` | O(2) | Only changed items' effects run |
|
|
630
|
+
| Proxy property access | O(1) | Per-property signal lookup |
|
|
631
|
+
| `ReactiveMap.get()` | O(1) | Per-key tracking |
|
|
632
|
+
|
|
633
|
+
**Key optimizations:**
|
|
541
634
|
- **Lazy evaluation** - Deriveds only compute when read
|
|
542
635
|
- **Version-based deduplication** - No duplicate dependency tracking
|
|
543
636
|
- **Linked list effect tree** - O(1) effect insertion/removal
|
|
544
637
|
- **Microtask batching** - Updates coalesce automatically
|
|
545
638
|
- **Per-property signals** - Fine-grained updates at any depth
|
|
639
|
+
- **FinalizationRegistry cleanup** - Automatic memory management
|
|
640
|
+
|
|
641
|
+
---
|
|
642
|
+
|
|
643
|
+
## Framework Comparison
|
|
644
|
+
|
|
645
|
+
| Feature | @rlabs-inc/signals | Svelte 5 | Vue 3 | Angular | Solid.js |
|
|
646
|
+
|---------|-------------------|----------|-------|---------|----------|
|
|
647
|
+
| `signal()` | `signal()` | `$state` | `ref()` | `signal()` | `createSignal()` |
|
|
648
|
+
| `derived()` | `derived()` | `$derived` | `computed()` | `computed()` | `createMemo()` |
|
|
649
|
+
| `effect()` | `effect()` | `$effect` | `watchEffect()` | `effect()` | `createEffect()` |
|
|
650
|
+
| Deep reactivity | `state()` | `$state` | `reactive()` | - | - |
|
|
651
|
+
| `linkedSignal()` | Yes | - | - | Yes | - |
|
|
652
|
+
| `createSelector()` | Yes | - | - | - | Yes |
|
|
653
|
+
| `effectScope()` | Yes | - | Yes | - | - |
|
|
654
|
+
| Compiler required | No | Yes | No | No | No |
|
|
655
|
+
| DOM integration | No | Yes | Yes | Yes | Yes |
|
|
656
|
+
|
|
657
|
+
---
|
|
658
|
+
|
|
659
|
+
## Low-Level API
|
|
660
|
+
|
|
661
|
+
For advanced use cases (framework authors, custom reactivity):
|
|
662
|
+
|
|
663
|
+
```typescript
|
|
664
|
+
import {
|
|
665
|
+
source, mutableSource, // Raw signal creation
|
|
666
|
+
get, set, // Track/update values
|
|
667
|
+
isDirty, // Check if needs update
|
|
668
|
+
markReactions, // Notify dependents
|
|
669
|
+
createEffect, // Raw effect creation
|
|
670
|
+
createDerived, // Raw derived creation
|
|
671
|
+
} from '@rlabs-inc/signals'
|
|
672
|
+
|
|
673
|
+
// Create a raw source (no .value wrapper)
|
|
674
|
+
const src = source(0)
|
|
675
|
+
|
|
676
|
+
// Read with tracking
|
|
677
|
+
const value = get(src)
|
|
678
|
+
|
|
679
|
+
// Write with notification
|
|
680
|
+
set(src, 10)
|
|
681
|
+
```
|
|
546
682
|
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
| Feature | Svelte 5 | @rlabs-inc/signals |
|
|
550
|
-
|---------|----------|-------------------|
|
|
551
|
-
| Compiler required | Yes | No |
|
|
552
|
-
| DOM integration | Yes | No |
|
|
553
|
-
| Fine-grained reactivity | Yes | Yes |
|
|
554
|
-
| Deep proxy reactivity | Yes | Yes |
|
|
555
|
-
| Reactive bindings | `bind:` directive | `bind()` function |
|
|
556
|
-
| Batching | Yes | Yes |
|
|
557
|
-
| Effect cleanup | Yes | Yes |
|
|
558
|
-
| TypeScript | Yes | Yes |
|
|
559
|
-
| Runs in Node/Bun | Needs adapter | Native |
|
|
683
|
+
---
|
|
560
684
|
|
|
561
685
|
## License
|
|
562
686
|
|
package/dist/core/types.d.ts
CHANGED
|
@@ -71,6 +71,20 @@ export interface DerivedSignal<T> extends ReadableSignal<T> {
|
|
|
71
71
|
}
|
|
72
72
|
/** Dispose function for effects */
|
|
73
73
|
export type DisposeFn = () => void;
|
|
74
|
+
/**
|
|
75
|
+
* Extract the inner type T from reactive wrappers.
|
|
76
|
+
*
|
|
77
|
+
* When given a union like `T | WritableSignal<T> | Binding<T>`, this extracts
|
|
78
|
+
* just T. Conditional types distribute over unions, so:
|
|
79
|
+
*
|
|
80
|
+
* ExtractInner<number | WritableSignal<number>> = number | number = number
|
|
81
|
+
*
|
|
82
|
+
* This is essential for bind() to correctly infer return types when given
|
|
83
|
+
* "Reactive<T>" union types (T | WritableSignal<T> | Binding<T> | ReadonlyBinding<T>).
|
|
84
|
+
*/
|
|
85
|
+
export type ExtractInner<T> = T extends WritableSignal<infer U> ? U : T extends ReadableSignal<infer U> ? U : T extends {
|
|
86
|
+
readonly value: infer U;
|
|
87
|
+
} ? U : T;
|
|
74
88
|
/** Type for uninitialized values */
|
|
75
89
|
export type Uninitialized = typeof UNINITIALIZED;
|
|
76
90
|
//# sourceMappingURL=types.d.ts.map
|
package/dist/core/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA;AAMnD,oDAAoD;AAGpD,MAAM,MAAM,MAAM,CAAC,CAAC,GAAG,GAAG,IAAI,CAAC,QAAQ,EAAE,GAAG,EAAE,QAAQ,EAAE,GAAG,KAAK,OAAO,CAAA;AAMvE,6CAA6C;AAC7C,MAAM,WAAW,MAAM;IACrB,uCAAuC;IACvC,CAAC,EAAE,MAAM,CAAA;IAET,yDAAyD;IACzD,EAAE,EAAE,MAAM,CAAA;CACX;AAMD,uCAAuC;AACvC,MAAM,WAAW,MAAM,CAAC,CAAC,GAAG,OAAO,CAAE,SAAQ,MAAM;IACjD,oBAAoB;IACpB,CAAC,EAAE,CAAC,CAAA;IAEJ,6CAA6C;IAC7C,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,CAAA;IAEjB,8DAA8D;IAC9D,SAAS,EAAE,QAAQ,EAAE,GAAG,IAAI,CAAA;IAE5B,kDAAkD;IAClD,EAAE,EAAE,MAAM,CAAA;CACX;AAMD,0DAA0D;AAC1D,MAAM,WAAW,QAAS,SAAQ,MAAM;IACtC,8BAA8B;IAC9B,EAAE,EAAE,QAAQ,GAAG,IAAI,CAAA;IAEnB,0DAA0D;IAC1D,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CAAA;CACtB;AAMD,iCAAiC;AACjC,MAAM,WAAW,OAAO,CAAC,CAAC,GAAG,OAAO,CAAE,SAAQ,MAAM,CAAC,CAAC,CAAC,EAAE,QAAQ;IAC/D,2BAA2B;IAC3B,EAAE,EAAE,MAAM,CAAC,CAAA;IAEX,gDAAgD;IAChD,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,CAAA;IAExB,+BAA+B;IAC/B,MAAM,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI,CAAA;CAChC;AAMD,2CAA2C;AAC3C,MAAM,MAAM,SAAS,GAAG,MAAM,IAAI,CAAA;AAElC,gCAAgC;AAChC,MAAM,MAAM,QAAQ,GAAG,MAAM,IAAI,GAAG,SAAS,CAAA;AAE7C,8BAA8B;AAC9B,MAAM,WAAW,MAAO,SAAQ,QAAQ;IACtC,sBAAsB;IACtB,EAAE,EAAE,QAAQ,GAAG,IAAI,CAAA;IAEnB,8CAA8C;IAC9C,QAAQ,EAAE,SAAS,GAAG,IAAI,CAAA;IAE1B,uCAAuC;IACvC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;IAErB,yBAAyB;IACzB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IAEpB,wBAAwB;IACxB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;IAEnB,8BAA8B;IAC9B,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;IAEnB,0BAA0B;IAC1B,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;CACpB;AAMD,mDAAmD;AACnD,MAAM,MAAM,KAAK,CAAC,CAAC,GAAG,OAAO,IAAI,MAAM,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAA;AAMvD,8CAA8C;AAC9C,MAAM,WAAW,cAAc,CAAC,CAAC;IAC/B,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAA;CAClB;AAED,6CAA6C;AAC7C,MAAM,WAAW,cAAc,CAAC,CAAC,CAAE,SAAQ,cAAc,CAAC,CAAC,CAAC;IAC1D,KAAK,EAAE,CAAC,CAAA;CACT;AAED,4CAA4C;AAC5C,MAAM,WAAW,aAAa,CAAC,CAAC,CAAE,SAAQ,cAAc,CAAC,CAAC,CAAC;CAAG;AAE9D,mCAAmC;AACnC,MAAM,MAAM,SAAS,GAAG,MAAM,IAAI,CAAA;AAMlC,oCAAoC;AACpC,MAAM,MAAM,aAAa,GAAG,OAAO,aAAa,CAAA"}
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -15,7 +15,7 @@ export { ReactiveDate } from './collections/date.js';
|
|
|
15
15
|
export { get, set, isDirty, setSignalStatus, markReactions, updateReaction, removeReactions, } from './reactivity/tracking.js';
|
|
16
16
|
export { DERIVED, EFFECT, RENDER_EFFECT, ROOT_EFFECT, BRANCH_EFFECT, USER_EFFECT, BLOCK_EFFECT, CLEAN, DIRTY, MAYBE_DIRTY, REACTION_IS_UPDATING, DESTROYED, INERT, EFFECT_RAN, EFFECT_PRESERVED, UNOWNED, DISCONNECTED, UNINITIALIZED, STALE_REACTION, STATE_SYMBOL, REACTIVE_MARKER, BINDING_SYMBOL, LINKED_SYMBOL, } from './core/constants.js';
|
|
17
17
|
export { activeReaction, activeEffect, untracking, writeVersion, readVersion, batchDepth, setActiveReaction, setActiveEffect, setUntracking, incrementWriteVersion, incrementReadVersion, incrementBatchDepth, decrementBatchDepth, getReadVersion, getWriteVersion, getBatchDepth, } from './core/globals.js';
|
|
18
|
-
export type { Signal, Source, Reaction, Derived, Effect, Value, ReadableSignal, WritableSignal, DerivedSignal, DisposeFn, CleanupFn, EffectFn, Equals, Uninitialized, } from './core/types.js';
|
|
18
|
+
export type { Signal, Source, Reaction, Derived, Effect, Value, ReadableSignal, WritableSignal, DerivedSignal, DisposeFn, CleanupFn, EffectFn, Equals, Uninitialized, ExtractInner, } from './core/types.js';
|
|
19
19
|
export type { Binding, ReadonlyBinding } from './primitives/bind.js';
|
|
20
20
|
export type { LinkedSignalOptions, LinkedSignalConfig } from './primitives/linked.js';
|
|
21
21
|
export type { SelectorFn } from './primitives/selector.js';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAoBA,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAA;AACvF,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAA;AACnF,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAA;AAC1F,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAA;AACrF,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAA;AACrE,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAA;AACzD,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;AAMpF,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAM1D,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,0BAA0B,CAAA;AAC/D,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,4BAA4B,CAAA;AAM5D,OAAO,EACL,MAAM,EACN,UAAU,EACV,YAAY,EACZ,aAAa,EACb,YAAY,EACZ,WAAW,EACX,YAAY,GACb,MAAM,0BAA0B,CAAA;AAMjC,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAA;AAClD,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAA;AAClD,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAA;AAMpD,OAAO,EACL,GAAG,EACH,GAAG,EACH,OAAO,EACP,eAAe,EACf,aAAa,EACb,cAAc,EACd,eAAe,GAChB,MAAM,0BAA0B,CAAA;AAMjC,OAAO,EAEL,OAAO,EACP,MAAM,EACN,aAAa,EACb,WAAW,EACX,aAAa,EACb,WAAW,EACX,YAAY,EAGZ,KAAK,EACL,KAAK,EACL,WAAW,EACX,oBAAoB,EACpB,SAAS,EACT,KAAK,EACL,UAAU,EACV,gBAAgB,EAGhB,OAAO,EACP,YAAY,EAGZ,aAAa,EACb,cAAc,EACd,YAAY,EACZ,eAAe,EACf,cAAc,EACd,aAAa,GACd,MAAM,qBAAqB,CAAA;AAM5B,OAAO,EACL,cAAc,EACd,YAAY,EACZ,UAAU,EACV,YAAY,EACZ,WAAW,EACX,UAAU,EAGV,iBAAiB,EACjB,eAAe,EACf,aAAa,EACb,qBAAqB,EACrB,oBAAoB,EACpB,mBAAmB,EACnB,mBAAmB,EAGnB,cAAc,EACd,eAAe,EACf,aAAa,GACd,MAAM,mBAAmB,CAAA;AAM1B,YAAY,EAEV,MAAM,EACN,MAAM,EACN,QAAQ,EACR,OAAO,EACP,MAAM,EACN,KAAK,EAGL,cAAc,EACd,cAAc,EACd,aAAa,EACb,SAAS,EACT,SAAS,EACT,QAAQ,EAGR,MAAM,EACN,aAAa,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAoBA,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAA;AACvF,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAA;AACnF,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAA;AAC1F,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAA;AACrF,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAA;AACrE,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAA;AACzD,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;AAMpF,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAM1D,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,0BAA0B,CAAA;AAC/D,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,4BAA4B,CAAA;AAM5D,OAAO,EACL,MAAM,EACN,UAAU,EACV,YAAY,EACZ,aAAa,EACb,YAAY,EACZ,WAAW,EACX,YAAY,GACb,MAAM,0BAA0B,CAAA;AAMjC,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAA;AAClD,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAA;AAClD,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAA;AAMpD,OAAO,EACL,GAAG,EACH,GAAG,EACH,OAAO,EACP,eAAe,EACf,aAAa,EACb,cAAc,EACd,eAAe,GAChB,MAAM,0BAA0B,CAAA;AAMjC,OAAO,EAEL,OAAO,EACP,MAAM,EACN,aAAa,EACb,WAAW,EACX,aAAa,EACb,WAAW,EACX,YAAY,EAGZ,KAAK,EACL,KAAK,EACL,WAAW,EACX,oBAAoB,EACpB,SAAS,EACT,KAAK,EACL,UAAU,EACV,gBAAgB,EAGhB,OAAO,EACP,YAAY,EAGZ,aAAa,EACb,cAAc,EACd,YAAY,EACZ,eAAe,EACf,cAAc,EACd,aAAa,GACd,MAAM,qBAAqB,CAAA;AAM5B,OAAO,EACL,cAAc,EACd,YAAY,EACZ,UAAU,EACV,YAAY,EACZ,WAAW,EACX,UAAU,EAGV,iBAAiB,EACjB,eAAe,EACf,aAAa,EACb,qBAAqB,EACrB,oBAAoB,EACpB,mBAAmB,EACnB,mBAAmB,EAGnB,cAAc,EACd,eAAe,EACf,aAAa,GACd,MAAM,mBAAmB,CAAA;AAM1B,YAAY,EAEV,MAAM,EACN,MAAM,EACN,QAAQ,EACR,OAAO,EACP,MAAM,EACN,KAAK,EAGL,cAAc,EACd,cAAc,EACd,aAAa,EACb,SAAS,EACT,SAAS,EACT,QAAQ,EAGR,MAAM,EACN,aAAa,EACb,YAAY,GACb,MAAM,iBAAiB,CAAA;AAExB,YAAY,EAAE,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAA;AACpE,YAAY,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAA;AACrF,YAAY,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAA;AAC1D,YAAY,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAA"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { WritableSignal, ReadableSignal } from '../core/types.js';
|
|
1
|
+
import type { WritableSignal, ReadableSignal, ExtractInner } from '../core/types.js';
|
|
2
2
|
/**
|
|
3
3
|
* A writable binding that forwards reads and writes to a source.
|
|
4
4
|
* Reading creates dependency on source, writing triggers source's reactions.
|
|
@@ -23,7 +23,7 @@ export declare function bind<T>(source: ReadableSignal<T>): ReadonlyBinding<T>;
|
|
|
23
23
|
export declare function bind<T>(source: Binding<T>): Binding<T>;
|
|
24
24
|
export declare function bind<T>(source: ReadonlyBinding<T>): ReadonlyBinding<T>;
|
|
25
25
|
export declare function bind<T>(source: () => T): ReadonlyBinding<T>;
|
|
26
|
-
export declare function bind<T>(source: T): Binding<T
|
|
26
|
+
export declare function bind<T>(source: T): Binding<ExtractInner<T>>;
|
|
27
27
|
/**
|
|
28
28
|
* Create an explicitly read-only binding.
|
|
29
29
|
* Attempting to write will throw an error at runtime.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bind.d.ts","sourceRoot":"","sources":["../../src/primitives/bind.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAU,MAAM,kBAAkB,CAAA;
|
|
1
|
+
{"version":3,"file":"bind.d.ts","sourceRoot":"","sources":["../../src/primitives/bind.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAU,YAAY,EAAE,MAAM,kBAAkB,CAAA;AAsB5F;;;GAGG;AACH,MAAM,WAAW,OAAO,CAAC,CAAC;IACxB,IAAI,KAAK,IAAI,CAAC,CAAA;IACd,IAAI,KAAK,CAAC,CAAC,EAAE,CAAC,EAAC;CAChB;AAED;;;GAGG;AACH,MAAM,WAAW,eAAe,CAAC,CAAC;IAChC,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAA;CAClB;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,OAAO,CAAC,OAAO,CAAC,CAEnE;AA0DD,wBAAgB,IAAI,CAAC,CAAC,EAAE,MAAM,EAAE,cAAc,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAA;AAC9D,wBAAgB,IAAI,CAAC,CAAC,EAAE,MAAM,EAAE,cAAc,CAAC,CAAC,CAAC,GAAG,eAAe,CAAC,CAAC,CAAC,CAAA;AACtE,wBAAgB,IAAI,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAA;AACvD,wBAAgB,IAAI,CAAC,CAAC,EAAE,MAAM,EAAE,eAAe,CAAC,CAAC,CAAC,GAAG,eAAe,CAAC,CAAC,CAAC,CAAA;AACvE,wBAAgB,IAAI,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,GAAG,eAAe,CAAC,CAAC,CAAC,CAAA;AAC5D,wBAAgB,IAAI,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAA;AA2D5D;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,YAAY,CAAC,CAAC,EAAE,MAAM,EAAE,cAAc,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,GAAG,eAAe,CAAC,CAAC,CAAC,CAQ1F;AAMD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,MAAM,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,GAAG,eAAe,CAAC,CAAC,CAAC,GAAG,CAAC,CAKvE;AAMD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,OAAO,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACvD,OAAO,EAAE,CAAC,GACT;KAAG,CAAC,IAAI,MAAM,CAAC,GAAG,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CAAE,CAU1C"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rlabs-inc/signals",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.3",
|
|
4
4
|
"description": "Production-grade fine-grained reactivity for TypeScript. A complete standalone mirror of Svelte 5's reactivity system - signals, effects, derived values, deep reactivity, reactive collections, and reactive bindings.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|