@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.
Files changed (50) hide show
  1. package/.ai-context.md +26 -5
  2. package/.cursorrules +8 -3
  3. package/.github/copilot-instructions.md +13 -4
  4. package/CLAUDE.md +191 -262
  5. package/README.md +268 -420
  6. package/archive/collection.ts +23 -25
  7. package/archive/computed.ts +5 -4
  8. package/archive/list.ts +21 -28
  9. package/archive/memo.ts +4 -2
  10. package/archive/state.ts +2 -1
  11. package/archive/store.ts +21 -32
  12. package/archive/task.ts +6 -9
  13. package/index.dev.js +411 -220
  14. package/index.js +1 -1
  15. package/index.ts +25 -8
  16. package/package.json +1 -1
  17. package/src/classes/collection.ts +103 -77
  18. package/src/classes/composite.ts +28 -33
  19. package/src/classes/computed.ts +90 -31
  20. package/src/classes/list.ts +39 -33
  21. package/src/classes/ref.ts +96 -0
  22. package/src/classes/state.ts +41 -8
  23. package/src/classes/store.ts +47 -30
  24. package/src/diff.ts +2 -1
  25. package/src/effect.ts +19 -9
  26. package/src/errors.ts +31 -1
  27. package/src/match.ts +5 -12
  28. package/src/resolve.ts +3 -2
  29. package/src/signal.ts +0 -1
  30. package/src/system.ts +159 -43
  31. package/src/util.ts +0 -10
  32. package/test/collection.test.ts +383 -67
  33. package/test/computed.test.ts +268 -11
  34. package/test/effect.test.ts +2 -2
  35. package/test/list.test.ts +249 -21
  36. package/test/ref.test.ts +381 -0
  37. package/test/state.test.ts +13 -13
  38. package/test/store.test.ts +473 -28
  39. package/types/index.d.ts +6 -5
  40. package/types/src/classes/collection.d.ts +27 -12
  41. package/types/src/classes/composite.d.ts +4 -4
  42. package/types/src/classes/computed.d.ts +17 -0
  43. package/types/src/classes/list.d.ts +6 -6
  44. package/types/src/classes/ref.d.ts +48 -0
  45. package/types/src/classes/state.d.ts +9 -0
  46. package/types/src/classes/store.d.ts +4 -4
  47. package/types/src/effect.d.ts +1 -2
  48. package/types/src/errors.d.ts +9 -1
  49. package/types/src/system.d.ts +40 -24
  50. 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**: Read-only derived arrays with item-level memoization and async support
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 # Read-only derived arrays (Collection)
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 Collection(todoList, todo =>
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 Collection(todoList, async (todo, abort) => {
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/store.ts - Object stores
36
- - src/computed.ts - Computed signals
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**: Read-only derived arrays with item-level memoization and async support (`new 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` - Read-only derived arrays with memoization
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 Collection(users, user => ({
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