@uistate/core 5.2.0 → 5.3.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.
Files changed (138) hide show
  1. package/package.json +5 -5
  2. package/queryClient.js +55 -0
  3. package/examples/001-counter/README.md +0 -44
  4. package/examples/001-counter/index.html +0 -33
  5. package/examples/002-counter-improved/README.md +0 -44
  6. package/examples/002-counter-improved/index.html +0 -47
  7. package/examples/003-input-reactive/README.md +0 -44
  8. package/examples/003-input-reactive/index.html +0 -33
  9. package/examples/004-computed-state/README.md +0 -45
  10. package/examples/004-computed-state/index.html +0 -65
  11. package/examples/005-conditional-rendering/README.md +0 -42
  12. package/examples/005-conditional-rendering/index.html +0 -39
  13. package/examples/006-list-rendering/README.md +0 -49
  14. package/examples/006-list-rendering/index.html +0 -63
  15. package/examples/007-form-validation/README.md +0 -52
  16. package/examples/007-form-validation/index.html +0 -102
  17. package/examples/008-undo-redo/README.md +0 -70
  18. package/examples/008-undo-redo/index.html +0 -108
  19. package/examples/009-localStorage-side-effects/README.md +0 -72
  20. package/examples/009-localStorage-side-effects/index.html +0 -57
  21. package/examples/010-decoupled-components/README.md +0 -74
  22. package/examples/010-decoupled-components/index.html +0 -93
  23. package/examples/011-async-patterns/README.md +0 -98
  24. package/examples/011-async-patterns/index.html +0 -132
  25. package/examples/028-counter-improved-eventTest/LICENSE +0 -55
  26. package/examples/028-counter-improved-eventTest/README.md +0 -131
  27. package/examples/028-counter-improved-eventTest/app/store.js +0 -9
  28. package/examples/028-counter-improved-eventTest/index.html +0 -49
  29. package/examples/028-counter-improved-eventTest/runtime/core/behaviors.runtime.js +0 -282
  30. package/examples/028-counter-improved-eventTest/runtime/core/eventState.js +0 -100
  31. package/examples/028-counter-improved-eventTest/runtime/core/eventStateNew.js +0 -149
  32. package/examples/028-counter-improved-eventTest/runtime/core/helpers.js +0 -212
  33. package/examples/028-counter-improved-eventTest/runtime/core/router.js +0 -271
  34. package/examples/028-counter-improved-eventTest/store.d.ts +0 -8
  35. package/examples/028-counter-improved-eventTest/style.css +0 -170
  36. package/examples/028-counter-improved-eventTest/tests/README.md +0 -208
  37. package/examples/028-counter-improved-eventTest/tests/counter.test.js +0 -116
  38. package/examples/028-counter-improved-eventTest/tests/eventTest.js +0 -176
  39. package/examples/028-counter-improved-eventTest/tests/generateTypes.js +0 -168
  40. package/examples/028-counter-improved-eventTest/tests/run.js +0 -20
  41. package/examples/030-todo-app-with-eventTest/LICENSE +0 -55
  42. package/examples/030-todo-app-with-eventTest/README.md +0 -121
  43. package/examples/030-todo-app-with-eventTest/app/router.js +0 -25
  44. package/examples/030-todo-app-with-eventTest/app/store.js +0 -16
  45. package/examples/030-todo-app-with-eventTest/app/views/home.js +0 -11
  46. package/examples/030-todo-app-with-eventTest/app/views/todoDemo.js +0 -88
  47. package/examples/030-todo-app-with-eventTest/index.html +0 -65
  48. package/examples/030-todo-app-with-eventTest/runtime/core/behaviors.runtime.js +0 -282
  49. package/examples/030-todo-app-with-eventTest/runtime/core/eventState.js +0 -100
  50. package/examples/030-todo-app-with-eventTest/runtime/core/eventStateNew.js +0 -149
  51. package/examples/030-todo-app-with-eventTest/runtime/core/helpers.js +0 -212
  52. package/examples/030-todo-app-with-eventTest/runtime/core/router.js +0 -271
  53. package/examples/030-todo-app-with-eventTest/store.d.ts +0 -18
  54. package/examples/030-todo-app-with-eventTest/style.css +0 -170
  55. package/examples/030-todo-app-with-eventTest/tests/README.md +0 -208
  56. package/examples/030-todo-app-with-eventTest/tests/eventTest.js +0 -176
  57. package/examples/030-todo-app-with-eventTest/tests/generateTypes.js +0 -189
  58. package/examples/030-todo-app-with-eventTest/tests/run.js +0 -20
  59. package/examples/030-todo-app-with-eventTest/tests/todos.test.js +0 -167
  60. package/examples/031-todo-app-with-eventTest/LICENSE +0 -55
  61. package/examples/031-todo-app-with-eventTest/README.md +0 -54
  62. package/examples/031-todo-app-with-eventTest/TUTORIAL.md +0 -390
  63. package/examples/031-todo-app-with-eventTest/WHY_EVENTSTATE.md +0 -777
  64. package/examples/031-todo-app-with-eventTest/app/bridges.js +0 -113
  65. package/examples/031-todo-app-with-eventTest/app/router.js +0 -26
  66. package/examples/031-todo-app-with-eventTest/app/store.js +0 -15
  67. package/examples/031-todo-app-with-eventTest/app/views/home.js +0 -46
  68. package/examples/031-todo-app-with-eventTest/app/views/todoDemo.js +0 -69
  69. package/examples/031-todo-app-with-eventTest/devtools/dock.js +0 -41
  70. package/examples/031-todo-app-with-eventTest/devtools/stateTracker.dock.js +0 -10
  71. package/examples/031-todo-app-with-eventTest/devtools/stateTracker.js +0 -246
  72. package/examples/031-todo-app-with-eventTest/devtools/telemetry.js +0 -104
  73. package/examples/031-todo-app-with-eventTest/devtools/typeGenerator.js +0 -339
  74. package/examples/031-todo-app-with-eventTest/index.html +0 -103
  75. package/examples/031-todo-app-with-eventTest/package-lock.json +0 -2184
  76. package/examples/031-todo-app-with-eventTest/package.json +0 -24
  77. package/examples/031-todo-app-with-eventTest/runtime/core/behaviors.runtime.js +0 -282
  78. package/examples/031-todo-app-with-eventTest/runtime/core/eventState.js +0 -100
  79. package/examples/031-todo-app-with-eventTest/runtime/core/eventStateNew.js +0 -149
  80. package/examples/031-todo-app-with-eventTest/runtime/core/helpers.js +0 -212
  81. package/examples/031-todo-app-with-eventTest/runtime/core/router.js +0 -271
  82. package/examples/031-todo-app-with-eventTest/runtime/extensions/boundary.js +0 -36
  83. package/examples/031-todo-app-with-eventTest/runtime/extensions/converge.js +0 -63
  84. package/examples/031-todo-app-with-eventTest/runtime/extensions/eventState.plus.js +0 -210
  85. package/examples/031-todo-app-with-eventTest/runtime/extensions/hydrate.js +0 -157
  86. package/examples/031-todo-app-with-eventTest/runtime/extensions/queryBinding.js +0 -69
  87. package/examples/031-todo-app-with-eventTest/runtime/forms/computed.js +0 -78
  88. package/examples/031-todo-app-with-eventTest/runtime/forms/meta.js +0 -51
  89. package/examples/031-todo-app-with-eventTest/runtime/forms/submitWithBoundary.js +0 -28
  90. package/examples/031-todo-app-with-eventTest/runtime/forms/validators.js +0 -55
  91. package/examples/031-todo-app-with-eventTest/store.d.ts +0 -23
  92. package/examples/031-todo-app-with-eventTest/style.css +0 -170
  93. package/examples/031-todo-app-with-eventTest/tests/README.md +0 -208
  94. package/examples/031-todo-app-with-eventTest/tests/eventTest.js +0 -176
  95. package/examples/031-todo-app-with-eventTest/tests/generateTypes.js +0 -191
  96. package/examples/031-todo-app-with-eventTest/tests/run.js +0 -20
  97. package/examples/031-todo-app-with-eventTest/tests/todos.test.js +0 -192
  98. package/examples/032-todo-app-with-eventTest/LICENSE +0 -55
  99. package/examples/032-todo-app-with-eventTest/README.md +0 -54
  100. package/examples/032-todo-app-with-eventTest/TUTORIAL.md +0 -390
  101. package/examples/032-todo-app-with-eventTest/WHY_EVENTSTATE.md +0 -777
  102. package/examples/032-todo-app-with-eventTest/app/actions/index.js +0 -153
  103. package/examples/032-todo-app-with-eventTest/app/bridges.js +0 -113
  104. package/examples/032-todo-app-with-eventTest/app/router.js +0 -26
  105. package/examples/032-todo-app-with-eventTest/app/store.js +0 -15
  106. package/examples/032-todo-app-with-eventTest/app/views/home.js +0 -46
  107. package/examples/032-todo-app-with-eventTest/app/views/todoDemo.js +0 -69
  108. package/examples/032-todo-app-with-eventTest/devtools/dock.js +0 -41
  109. package/examples/032-todo-app-with-eventTest/devtools/stateTracker.dock.js +0 -10
  110. package/examples/032-todo-app-with-eventTest/devtools/stateTracker.js +0 -246
  111. package/examples/032-todo-app-with-eventTest/devtools/telemetry.js +0 -104
  112. package/examples/032-todo-app-with-eventTest/devtools/typeGenerator.js +0 -339
  113. package/examples/032-todo-app-with-eventTest/index.html +0 -87
  114. package/examples/032-todo-app-with-eventTest/package-lock.json +0 -2184
  115. package/examples/032-todo-app-with-eventTest/package.json +0 -24
  116. package/examples/032-todo-app-with-eventTest/runtime/core/behaviors.runtime.js +0 -282
  117. package/examples/032-todo-app-with-eventTest/runtime/core/eventState.js +0 -100
  118. package/examples/032-todo-app-with-eventTest/runtime/core/eventStateNew.js +0 -149
  119. package/examples/032-todo-app-with-eventTest/runtime/core/helpers.js +0 -212
  120. package/examples/032-todo-app-with-eventTest/runtime/core/router.js +0 -271
  121. package/examples/032-todo-app-with-eventTest/runtime/extensions/boundary.js +0 -36
  122. package/examples/032-todo-app-with-eventTest/runtime/extensions/converge.js +0 -63
  123. package/examples/032-todo-app-with-eventTest/runtime/extensions/eventState.plus.js +0 -210
  124. package/examples/032-todo-app-with-eventTest/runtime/extensions/hydrate.js +0 -157
  125. package/examples/032-todo-app-with-eventTest/runtime/extensions/queryBinding.js +0 -69
  126. package/examples/032-todo-app-with-eventTest/runtime/forms/computed.js +0 -78
  127. package/examples/032-todo-app-with-eventTest/runtime/forms/meta.js +0 -51
  128. package/examples/032-todo-app-with-eventTest/runtime/forms/submitWithBoundary.js +0 -28
  129. package/examples/032-todo-app-with-eventTest/runtime/forms/validators.js +0 -55
  130. package/examples/032-todo-app-with-eventTest/store.d.ts +0 -23
  131. package/examples/032-todo-app-with-eventTest/style.css +0 -170
  132. package/examples/032-todo-app-with-eventTest/tests/README.md +0 -208
  133. package/examples/032-todo-app-with-eventTest/tests/eventTest.js +0 -176
  134. package/examples/032-todo-app-with-eventTest/tests/generateTypes.js +0 -191
  135. package/examples/032-todo-app-with-eventTest/tests/run.js +0 -20
  136. package/examples/032-todo-app-with-eventTest/tests/todos.test.js +0 -192
  137. package/playground/exercise001.html +0 -38
  138. package/playground/exercise002.html +0 -49
@@ -1,390 +0,0 @@
1
- # EventState Tutorial
2
-
3
- Learn how to build reactive web applications with EventState's fine-grained state management.
4
-
5
- ## Table of Contents
6
-
7
- 1. [Core Concepts](#core-concepts)
8
- 2. [Getting Started](#getting-started)
9
- 3. [Architecture Patterns](#architecture-patterns)
10
- 4. [Advanced Features](#advanced-features)
11
- 5. [Comparison with Other Frameworks](#comparison)
12
-
13
- ---
14
-
15
- ## Core Concepts
16
-
17
- ### 1. Fine-Grained Reactivity
18
-
19
- EventState uses **path-based subscriptions** for surgical DOM updates:
20
-
21
- ```javascript
22
- // Subscribe to specific paths
23
- store.subscribe('domain.todos.items', render); // Only updates when todos change
24
- store.subscribe('ui.theme', updateTheme); // Only updates when theme changes
25
- ```
26
-
27
- **Key differences from other frameworks:**
28
- - ❌ No virtual DOM diffing
29
- - ❌ No component-level re-renders
30
- - ✅ Direct path → handler mapping
31
- - ✅ Update only what changed
32
-
33
- ### 2. Intent-Based Architecture
34
-
35
- EventState separates **what happened** (intent) from **what to do** (bridge):
36
-
37
- ```
38
- UI Event → intent.* → Bridge → domain.* → View Update
39
- ```
40
-
41
- **Benefits:**
42
- - ✅ Unidirectional data flow (like Redux)
43
- - ✅ No boilerplate (unlike Redux)
44
- - ✅ Testable business logic (bridges are pure functions)
45
- - ✅ Decoupled UI from domain logic
46
-
47
- ### 3. Progressive API
48
-
49
- Start simple, add complexity only when needed:
50
-
51
- **Declarative** (for simple interactions):
52
- ```html
53
- <button data-on="click: addTodo()">Add</button>
54
- ```
55
-
56
- **Imperative** (for complex views):
57
- ```javascript
58
- store.subscribe('domain.todos.items', (items) => {
59
- // Custom rendering logic
60
- });
61
- ```
62
-
63
- ---
64
-
65
- ## Getting Started
66
-
67
-
68
- ### Quick Start
69
-
70
- **1. Create a store:**
71
- ```javascript
72
- import { createEventState } from './runtime/core/eventState.js';
73
-
74
- const store = createEventState({
75
- ui: { count: 0 },
76
- domain: { todos: [] }
77
- });
78
- ```
79
-
80
- **2. Subscribe to changes:**
81
- ```javascript
82
- store.subscribe('ui.count', (count) => {
83
- document.getElementById('count').textContent = count;
84
- });
85
- ```
86
-
87
- **3. Update state:**
88
- ```javascript
89
- button.onclick = () => {
90
- store.set('ui.count', store.get('ui.count') + 1);
91
- };
92
- ```
93
-
94
- That's it! No build step, no framework, just reactive data.
95
-
96
- ---
97
-
98
- ## Architecture Patterns
99
-
100
- ### The Intent-Bridge-Domain Pattern
101
-
102
- **Step 1: UI fires an intent**
103
- ```javascript
104
- // User clicks "Add Todo"
105
- store.set('intent.todo.add', { text: 'Buy milk' });
106
- ```
107
-
108
- **Step 2: Bridge handles the intent**
109
- ```javascript
110
- // app/bridges.js
111
- store.subscribe('intent.todo.add', ({ text }) => {
112
- const items = store.get('domain.todos.items') || [];
113
- store.set('domain.todos.items', [...items, { id: Date.now(), text }]);
114
- });
115
- ```
116
-
117
- **Step 3: View reacts to domain change**
118
- ```javascript
119
- // app/views/todoDemo.js
120
- store.subscribe('domain.todos.items', (items) => {
121
- renderTodoList(items);
122
- });
123
- ```
124
-
125
- **Why this pattern?**
126
- - ✅ Testable (test bridges in isolation)
127
- - ✅ Auditable (log all intents)
128
- - ✅ Flexible (change behavior without touching UI)
129
-
130
- ---
131
-
132
- ## Advanced Features
133
-
134
- ### 1. Wildcard Subscriptions
135
-
136
- ```javascript
137
- // Listen to all state changes
138
- store.subscribe('**', (value, path) => {
139
- console.log(`[state] ${path}`, value);
140
- });
141
-
142
- // Listen to all intents
143
- store.subscribe('intent.**', (value, path) => {
144
- console.log(`[intent] ${path}`, value);
145
- });
146
- ```
147
-
148
- ### 2. Batch Updates
149
-
150
- ```javascript
151
- import { upgradeEventState } from './runtime/extensions/eventState.plus.js';
152
-
153
- const storePlus = upgradeEventState(store);
154
-
155
- storePlus.setMany({
156
- 'ui.loading': false,
157
- 'domain.user': userData,
158
- 'ui.error': null
159
- });
160
- ```
161
-
162
- ### 3. Router Integration
163
-
164
- ```javascript
165
- import { createRouter } from './runtime/core/router.js';
166
-
167
- const router = createRouter({
168
- routes: [
169
- { path: '/', view: 'home', component: Home },
170
- { path: '/todos', view: 'todos', component: TodoList }
171
- ],
172
- store,
173
- rootSelector: '[data-route-root]'
174
- });
175
-
176
- router.start();
177
- ```
178
-
179
- ### 4. Built-in Telemetry
180
-
181
- ```javascript
182
- // All state changes are automatically logged in dev mode
183
- // Click "Console" button in dev dock to copy logs
184
-
185
- // Or access programmatically:
186
- window.__telemetry.get(); // Get all logs
187
- window.__telemetry.copy(); // Copy to clipboard
188
- ```
189
-
190
- ---
191
-
192
- ## Comparison
193
-
194
- ### Why Choose EventState?
195
-
196
- #### 1. No Common React Bugs
197
-
198
- **Stale Closures**
199
- ```javascript
200
- // React problem:
201
- const [count, setCount] = useState(0);
202
- setTimeout(() => console.log(count), 1000); // Stale!
203
-
204
- // EventState framework:
205
- store.subscribe('ui.count', (val) => console.log(val)); // Always fresh
206
- ```
207
-
208
- **Dependency Arrays**
209
- ```javascript
210
- // React:
211
- useEffect(() => { /* ... */ }, [dep1, dep2, dep3]); // Miss one? Bug!
212
-
213
- // EventState framework:
214
- store.subscribe('path.to.dep', handler); // Explicit, no guessing
215
- ```
216
-
217
- **Prop Drilling**
218
- ```javascript
219
- // React: <A> → <B> → <C> → <D> (pass props 4 levels)
220
- // EventState framework: Any component reads store.get('shared.data')
221
- ```
222
-
223
- **Re-render Debugging**
224
- ```javascript
225
- // EventState: Only subscribed handlers run
226
- store.subscribe('ui.count', updateCount); // Only this runs when count changes
227
-
228
- // React: Entire component tree may re-render
229
- // Need React DevTools to debug why
230
- ```
231
-
232
- #### 2. Performance by Default
233
-
234
- **Other frameworks require optimization:**
235
- ```javascript
236
- // React: Manual memoization
237
- const MemoizedComponent = memo(Component);
238
- const memoizedValue = useMemo(() => compute(a, b), [a, b]);
239
- const memoizedCallback = useCallback(() => {}, [deps]);
240
-
241
- // Angular: Change detection strategy
242
- @Component({ changeDetection: ChangeDetectionStrategy.OnPush })
243
- ```
244
-
245
- **EventState: Fast by default**
246
- ```javascript
247
- // Direct DOM updates, no virtual DOM
248
- // Only subscribed handlers run
249
- // No manual optimization needed
250
- store.subscribe('ui.count', (val) => el.textContent = val);
251
- ```
252
-
253
- #### 3. Less Boilerplate
254
-
255
- **Redux:**
256
- ```javascript
257
- // actions.js
258
- export const ADD_TODO = 'ADD_TODO';
259
- export const addTodo = (text) => ({ type: ADD_TODO, text });
260
-
261
- // reducers.js
262
- export default function todos(state = [], action) {
263
- switch (action.type) {
264
- case ADD_TODO:
265
- return [...state, { id: Date.now(), text: action.text }];
266
- default:
267
- return state;
268
- }
269
- }
270
-
271
- // component.js
272
- const mapStateToProps = (state) => ({ todos: state.todos });
273
- const mapDispatchToProps = { addTodo };
274
- export default connect(mapStateToProps, mapDispatchToProps)(TodoList);
275
- ```
276
-
277
- **EventState:**
278
- ```javascript
279
- // bridges.js
280
- store.subscribe('intent.todo.add', ({ text }) => {
281
- const items = store.get('domain.todos.items') || [];
282
- store.set('domain.todos.items', [...items, { id: Date.now(), text }]);
283
- });
284
- ```
285
-
286
- **3 files vs 1 function.**
287
-
288
- #### 4. Built-in Observability
289
-
290
- ```javascript
291
- // See every state change (one line)
292
- store.subscribe('**', (val, path) => console.log('[state]', path, val));
293
-
294
- // Time-travel debugging
295
- const history = [];
296
- store.subscribe('**', (val, path) => history.push({ path, val }));
297
- history.forEach(({ path, val }) => store.set(path, val)); // Replay
298
-
299
- // State snapshot
300
- const snapshot = store.get(''); // Entire state tree
301
- ```
302
-
303
- **No browser extensions needed** - everything is built-in.
304
-
305
- #### 5. Framework-Agnostic
306
-
307
- ```javascript
308
- // Works in vanilla JS
309
- store.set('count', 1);
310
-
311
- // Works with React
312
- function Counter() {
313
- const [count, setCount] = useState(store.get('count'));
314
- useEffect(() => store.subscribe('count', setCount), []);
315
- return <div>{count}</div>;
316
- }
317
-
318
- // Works with Web Components
319
- class MyCounter extends HTMLElement {
320
- connectedCallback() {
321
- this.unsub = store.subscribe('count', (val) => {
322
- this.textContent = val;
323
- });
324
- }
325
- }
326
-
327
- // Works with any build tool (or none)
328
- ```
329
-
330
- ---
331
-
332
- ## Feature Comparison
333
-
334
- | Feature | React | Redux | Vue | Solid | EventState |
335
- |---------|-------|-------|-----|-------|------------|
336
- | Fine-grained updates | ❌ | ❌ | ⚠️ | ✅ | ✅ |
337
- | No boilerplate | ⚠️ | ❌ | ⚠️ | ✅ | ✅ |
338
- | Framework-agnostic | ❌ | ⚠️ | ❌ | ⚠️ | ✅ |
339
- | Built-in time-travel | ❌ | ✅ | ❌ | ❌ | ✅ |
340
- | Wildcard subscriptions | ❌ | ❌ | ❌ | ❌ | ✅ |
341
- | Bundle size | 45KB | 3KB | 34KB | 7KB | <1KB |
342
- | Learning curve | High | Very High | Medium | Medium | Low |
343
-
344
- ---
345
-
346
- ## What's Next
347
-
348
- ### Current Status
349
-
350
- **What EventState has today:**
351
- - ✅ Solid reactivity primitive (~200 lines)
352
- - ✅ Clean architecture (intent → bridge → domain)
353
- - ✅ Low complexity (no build step required)
354
- - ✅ Good performance (fine-grained updates)
355
- - ✅ Generic router (`runtime/core/router.js`)
356
- - ✅ Form utilities (`runtime/forms/`)
357
- - ✅ Dev tools (telemetry, state tracker)
358
-
359
- ### Roadmap
360
-
361
- **In Development:**
362
- - TypeScript definitions
363
- - Component abstraction layer
364
- - Comprehensive test suite
365
- - npm package (`@uistate/core`)
366
-
367
- **Planned:**
368
- - Separate packages (`@uistate/router`, `@uistate/forms`)
369
- - VS Code extension (path autocomplete)
370
- - Documentation site
371
- - SSR adapter
372
-
373
- ---
374
-
375
- ## Learn More
376
-
377
- - **[WHY_EVENTSTATE.md](./WHY_EVENTSTATE.md)** - Philosophy and comparisons
378
- - **[runtime/core/eventState.js](./runtime/core/eventState.js)** - Source code (~200 lines)
379
- - **[app/bridges.js](./app/bridges.js)** - Real-world patterns
380
- - **[runtime/core/router.js](./runtime/core/router.js)** - Generic SPA router
381
-
382
- ---
383
-
384
- ## Contributing
385
-
386
- EventState is in active development. Feedback, issues, and contributions are welcome!
387
-
388
- ---
389
-
390
- *EventState: Fine-grained reactivity without the complexity.*