@zeix/cause-effect 0.17.0 → 0.17.2
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/.ai-context.md +26 -5
- package/.cursorrules +8 -3
- package/.github/copilot-instructions.md +13 -4
- package/CLAUDE.md +191 -262
- package/README.md +268 -420
- package/archive/collection.ts +23 -25
- package/archive/computed.ts +5 -4
- package/archive/list.ts +21 -28
- package/archive/memo.ts +4 -2
- package/archive/state.ts +2 -1
- package/archive/store.ts +21 -32
- package/archive/task.ts +6 -9
- package/index.dev.js +411 -220
- package/index.js +1 -1
- package/index.ts +25 -8
- package/package.json +1 -1
- package/src/classes/collection.ts +103 -77
- package/src/classes/composite.ts +28 -33
- package/src/classes/computed.ts +90 -31
- package/src/classes/list.ts +39 -33
- package/src/classes/ref.ts +96 -0
- package/src/classes/state.ts +41 -8
- package/src/classes/store.ts +47 -30
- package/src/diff.ts +2 -1
- package/src/effect.ts +19 -9
- package/src/errors.ts +31 -1
- package/src/match.ts +5 -12
- package/src/resolve.ts +3 -2
- package/src/signal.ts +0 -1
- package/src/system.ts +159 -43
- package/src/util.ts +0 -10
- package/test/collection.test.ts +383 -67
- package/test/computed.test.ts +268 -11
- package/test/effect.test.ts +2 -2
- package/test/list.test.ts +249 -21
- package/test/ref.test.ts +381 -0
- package/test/state.test.ts +13 -13
- package/test/store.test.ts +473 -28
- package/types/index.d.ts +6 -5
- package/types/src/classes/collection.d.ts +27 -12
- package/types/src/classes/composite.d.ts +4 -4
- package/types/src/classes/computed.d.ts +17 -0
- package/types/src/classes/list.d.ts +6 -6
- package/types/src/classes/ref.d.ts +48 -0
- package/types/src/classes/state.d.ts +9 -0
- package/types/src/classes/store.d.ts +4 -4
- package/types/src/effect.d.ts +1 -2
- package/types/src/errors.d.ts +9 -1
- package/types/src/system.d.ts +40 -24
- package/types/src/util.d.ts +1 -3
package/.ai-context.md
CHANGED
|
@@ -9,10 +9,11 @@ Cause & Effect is a modern reactive state management library for JavaScript/Type
|
|
|
9
9
|
### Signal Types
|
|
10
10
|
- **Signal**: Base interface with `.get()` method for value access
|
|
11
11
|
- **State**: Mutable signals for primitive values (numbers, strings, booleans)
|
|
12
|
+
- **Ref**: Signal wrappers for external objects that change outside the reactive system (DOM elements, Map, Set, Date, third-party objects)
|
|
13
|
+
- **Computed**: Read-only derived signals with automatic memoization, reducer capabilities and async handling
|
|
12
14
|
- **Store**: Mutable signals for objects with individually reactive properties
|
|
13
15
|
- **List**: Mutable signals for arrays with individually reactive items
|
|
14
|
-
- **Collection**:
|
|
15
|
-
- **Computed**: Read-only derived signals with automatic memoization, reducer capabilities and asyc handling
|
|
16
|
+
- **Collection**: Interface for reactive array-like collections (implemented by DerivedCollection)
|
|
16
17
|
- **Effect**: Side effect handlers that react to signal changes
|
|
17
18
|
|
|
18
19
|
### Key Principles
|
|
@@ -29,9 +30,10 @@ cause-effect/
|
|
|
29
30
|
├── src/
|
|
30
31
|
│ ├── classes/
|
|
31
32
|
│ │ ├── state.ts # Mutable state signals (State)
|
|
33
|
+
│ │ ├── ref.ts # Signal wrapper for external objects (Ref)
|
|
32
34
|
│ │ ├── store.ts # Object stores with reactive properties
|
|
33
35
|
│ │ ├── list.ts # Array stores with stable keys (List)
|
|
34
|
-
│ │ ├── collection.ts #
|
|
36
|
+
│ │ ├── collection.ts # Collection interface and DerivedCollection
|
|
35
37
|
│ │ └── computed.ts # Computed/derived signals (Memo and Task)
|
|
36
38
|
| ├── signal.ts # Base signal types and utilities
|
|
37
39
|
│ ├── effect.ts # Effect system (createEffect)
|
|
@@ -55,6 +57,10 @@ const count = new State(42)
|
|
|
55
57
|
const name = new State('Alice')
|
|
56
58
|
const actions = new State<'increment' | 'decrement' | 'reset'>('reset')
|
|
57
59
|
|
|
60
|
+
// Ref signals for external objects
|
|
61
|
+
const elementRef = new Ref(document.getElementById('status'))
|
|
62
|
+
const cacheRef = new Ref(new Map([['key', 'value']]))
|
|
63
|
+
|
|
58
64
|
// Store signals for objects
|
|
59
65
|
const user = createStore({ name: 'Alice', age: 30 })
|
|
60
66
|
|
|
@@ -181,15 +187,19 @@ const firstTodo = todoList.byKey('task1')
|
|
|
181
187
|
firstTodo?.completed.set(true) // Mark completed
|
|
182
188
|
|
|
183
189
|
// Collections for read-only derived data
|
|
184
|
-
const completedTodos = new
|
|
190
|
+
const completedTodos = new DerivedCollection(todoList, todo =>
|
|
185
191
|
todo.completed ? { ...todo, status: 'done' } : null
|
|
186
192
|
).filter(Boolean) // Remove null values
|
|
187
193
|
|
|
188
194
|
// Async collections for enhanced data
|
|
189
|
-
const todoWithDetails = new
|
|
195
|
+
const todoWithDetails = new DerivedCollection(todoList, async (todo, abort) => {
|
|
190
196
|
const response = await fetch(`/todos/${todo.id}/details`, { signal: abort })
|
|
191
197
|
return { ...todo, details: await response.json() }
|
|
192
198
|
})
|
|
199
|
+
|
|
200
|
+
// Element collections for DOM reactivity
|
|
201
|
+
const buttons = createElementCollection(document.body, 'button')
|
|
202
|
+
const inputs = createElementCollection(form, 'input[type="text"]')
|
|
193
203
|
```
|
|
194
204
|
|
|
195
205
|
### Derived State
|
|
@@ -265,6 +275,17 @@ const processedItems = items.deriveCollection(item => ({
|
|
|
265
275
|
const finalResults = processedItems.deriveCollection(item =>
|
|
266
276
|
item.processed ? { summary: `${item.name} at ${item.timestamp}` } : null
|
|
267
277
|
).filter(Boolean)
|
|
278
|
+
|
|
279
|
+
// Ref signal manual notifications
|
|
280
|
+
elementRef.notify() // Notify when DOM element changes externally
|
|
281
|
+
cacheRef.notify() // Notify when Map/Set changes externally
|
|
282
|
+
|
|
283
|
+
// Resource management with watch hooks
|
|
284
|
+
signal.on('watch', () => {
|
|
285
|
+
console.log('Setting up resource...')
|
|
286
|
+
const resource = createResource()
|
|
287
|
+
return () => resource.cleanup() // Called when no effects watch this signal
|
|
288
|
+
})
|
|
268
289
|
```
|
|
269
290
|
|
|
270
291
|
## Build and Development
|
package/.cursorrules
CHANGED
|
@@ -6,9 +6,11 @@ TypeScript/JavaScript reactive state management library using signals pattern
|
|
|
6
6
|
## Core Concepts
|
|
7
7
|
- Signals: Base reactive primitives with .get() method
|
|
8
8
|
- State: new State() for primitives/simple values
|
|
9
|
+
- Ref: new Ref() for external objects (DOM, Map, Set) requiring manual .notify()
|
|
9
10
|
- Computed: new Memo() for derived/memoized values and new Task() for asynchronous computations
|
|
10
11
|
- Store: createStore() for objects with reactive properties
|
|
11
12
|
- List: new List() for arrays with stable keys and reactive items
|
|
13
|
+
- Collection: Interface for reactive collections (DerivedCollection, ElementCollection)
|
|
12
14
|
- Effects: createEffect() for side effects
|
|
13
15
|
|
|
14
16
|
## Code Style
|
|
@@ -31,9 +33,12 @@ TypeScript/JavaScript reactive state management library using signals pattern
|
|
|
31
33
|
|
|
32
34
|
## File Structure
|
|
33
35
|
- src/signal.ts - Base signal types
|
|
34
|
-
- src/state.ts - Mutable state signals
|
|
35
|
-
- src/
|
|
36
|
-
- src/
|
|
36
|
+
- src/classes/state.ts - Mutable state signals
|
|
37
|
+
- src/classes/ref.ts - Signal wrappers for external objects
|
|
38
|
+
- src/classes/store.ts - Object stores
|
|
39
|
+
- src/classes/list.ts - Array stores with stable keys
|
|
40
|
+
- src/classes/collection.ts - Collection interface and DerivedCollection
|
|
41
|
+
- src/classes/computed.ts - Computed signals
|
|
37
42
|
- src/effect.ts - Effect system
|
|
38
43
|
- src/system.ts - Core reactivity (watchers, batching)
|
|
39
44
|
- index.ts - Main exports
|
|
@@ -8,18 +8,20 @@ Cause & Effect is a reactive state management library for JavaScript/TypeScript
|
|
|
8
8
|
|
|
9
9
|
- **Signals**: Base reactive primitives with `.get()` method
|
|
10
10
|
- **State**: Mutable signals for primitive values (`new State()`)
|
|
11
|
+
- **Ref**: Signal wrappers for external objects that change outside reactive system (`new Ref()`)
|
|
11
12
|
- **Computed**: Derived read-only signals with memoization, reducer capabilities and async support (`new Memo()`, `new Task()`)
|
|
12
13
|
- **Store**: Mutable signals for objects with reactive properties (`createStore()`)
|
|
13
14
|
- **List**: Mutable signals for arrays with stable keys and reactive entries (`new List()`)
|
|
14
|
-
- **Collection**:
|
|
15
|
+
- **Collection**: Interface for reactive collections (implemented by `DerivedCollection`)
|
|
15
16
|
- **Effects**: Side effect handlers that react to signal changes (`createEffect()`)
|
|
16
17
|
|
|
17
18
|
## Key Files Structure
|
|
18
19
|
|
|
19
20
|
- `src/classes/state.ts` - Mutable state signals
|
|
21
|
+
- `src/classes/ref.ts` - Signal wrappers for external objects (DOM, Map, Set, etc.)
|
|
20
22
|
- `src/classes/store.ts` - Object stores with reactive properties
|
|
21
23
|
- `src/classes/list.ts` - Array stores with stable keys and reactive items
|
|
22
|
-
- `src/classes/collection.ts` -
|
|
24
|
+
- `src/classes/collection.ts` - Collection interface and DerivedCollection implementation
|
|
23
25
|
- `src/classes/computed.ts` - Computed/derived signals
|
|
24
26
|
- `src/signal.ts` - Base signal types and utilities
|
|
25
27
|
- `src/effect.ts` - Effect system
|
|
@@ -77,6 +79,10 @@ const count = new State(42)
|
|
|
77
79
|
const name = new State('Alice')
|
|
78
80
|
const actions = new State<'increment' | 'decrement'>('increment')
|
|
79
81
|
|
|
82
|
+
// Ref for external objects
|
|
83
|
+
const elementRef = new Ref(document.getElementById('status'))
|
|
84
|
+
const cacheRef = new Ref(new Map())
|
|
85
|
+
|
|
80
86
|
// Store for objects
|
|
81
87
|
const user = createStore({ name: 'Alice', age: 30 })
|
|
82
88
|
|
|
@@ -145,7 +151,6 @@ function isSignal<T extends {}>(value: unknown): value is Signal<T>
|
|
|
145
151
|
const items = new List(['a', 'b', 'c'])
|
|
146
152
|
|
|
147
153
|
// String prefix keys
|
|
148
|
-
// Lists with stable keys
|
|
149
154
|
const items = new List(['apple', 'banana'], 'fruit')
|
|
150
155
|
// Creates keys: 'fruit0', 'fruit1'
|
|
151
156
|
|
|
@@ -156,7 +161,7 @@ const users = new List([
|
|
|
156
161
|
], user => user.id) // Uses user.id as stable key
|
|
157
162
|
|
|
158
163
|
// Collections derived from lists
|
|
159
|
-
const userProfiles = new
|
|
164
|
+
const userProfiles = new DerivedCollection(users, user => ({
|
|
160
165
|
...user,
|
|
161
166
|
displayName: `${user.name} (ID: ${user.id})`
|
|
162
167
|
}))
|
|
@@ -168,6 +173,10 @@ const activeUserSummaries = users
|
|
|
168
173
|
.filter(Boolean)
|
|
169
174
|
```
|
|
170
175
|
|
|
176
|
+
## Resource Management
|
|
177
|
+
|
|
178
|
+
All signals support `.on('watch', callback)` for lazy resource allocation. Resources are only created when signals are accessed by effects and automatically cleaned up when no longer watched.
|
|
179
|
+
|
|
171
180
|
## When suggesting code:
|
|
172
181
|
1. Follow the established patterns for signal creation and usage
|
|
173
182
|
2. Use proper TypeScript types and generics
|