@uistate/examples 1.0.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/README.md +40 -0
- package/cssState/.gitkeep +0 -0
- package/eventState/001-counter/README.md +44 -0
- package/eventState/001-counter/index.html +33 -0
- package/eventState/002-counter-improved/README.md +44 -0
- package/eventState/002-counter-improved/index.html +47 -0
- package/eventState/003-input-reactive/README.md +44 -0
- package/eventState/003-input-reactive/index.html +33 -0
- package/eventState/004-computed-state/README.md +45 -0
- package/eventState/004-computed-state/index.html +65 -0
- package/eventState/005-conditional-rendering/README.md +42 -0
- package/eventState/005-conditional-rendering/index.html +39 -0
- package/eventState/006-list-rendering/README.md +49 -0
- package/eventState/006-list-rendering/index.html +63 -0
- package/eventState/007-form-validation/README.md +52 -0
- package/eventState/007-form-validation/index.html +102 -0
- package/eventState/008-undo-redo/README.md +70 -0
- package/eventState/008-undo-redo/index.html +108 -0
- package/eventState/009-localStorage-side-effects/README.md +72 -0
- package/eventState/009-localStorage-side-effects/index.html +57 -0
- package/eventState/010-decoupled-components/README.md +74 -0
- package/eventState/010-decoupled-components/index.html +93 -0
- package/eventState/011-async-patterns/README.md +98 -0
- package/eventState/011-async-patterns/index.html +132 -0
- package/eventState/028-counter-improved-eventTest/LICENSE +55 -0
- package/eventState/028-counter-improved-eventTest/README.md +131 -0
- package/eventState/028-counter-improved-eventTest/app/store.js +9 -0
- package/eventState/028-counter-improved-eventTest/index.html +49 -0
- package/eventState/028-counter-improved-eventTest/runtime/core/behaviors.runtime.js +282 -0
- package/eventState/028-counter-improved-eventTest/runtime/core/eventState.js +100 -0
- package/eventState/028-counter-improved-eventTest/runtime/core/eventStateNew.js +149 -0
- package/eventState/028-counter-improved-eventTest/runtime/core/helpers.js +212 -0
- package/eventState/028-counter-improved-eventTest/runtime/core/router.js +271 -0
- package/eventState/028-counter-improved-eventTest/store.d.ts +8 -0
- package/eventState/028-counter-improved-eventTest/style.css +170 -0
- package/eventState/028-counter-improved-eventTest/tests/README.md +208 -0
- package/eventState/028-counter-improved-eventTest/tests/counter.test.js +116 -0
- package/eventState/028-counter-improved-eventTest/tests/eventTest.js +176 -0
- package/eventState/028-counter-improved-eventTest/tests/generateTypes.js +168 -0
- package/eventState/028-counter-improved-eventTest/tests/run.js +20 -0
- package/eventState/030-todo-app-with-eventTest/LICENSE +55 -0
- package/eventState/030-todo-app-with-eventTest/README.md +121 -0
- package/eventState/030-todo-app-with-eventTest/app/router.js +25 -0
- package/eventState/030-todo-app-with-eventTest/app/store.js +16 -0
- package/eventState/030-todo-app-with-eventTest/app/views/home.js +11 -0
- package/eventState/030-todo-app-with-eventTest/app/views/todoDemo.js +88 -0
- package/eventState/030-todo-app-with-eventTest/index.html +65 -0
- package/eventState/030-todo-app-with-eventTest/runtime/core/behaviors.runtime.js +282 -0
- package/eventState/030-todo-app-with-eventTest/runtime/core/eventState.js +100 -0
- package/eventState/030-todo-app-with-eventTest/runtime/core/eventStateNew.js +149 -0
- package/eventState/030-todo-app-with-eventTest/runtime/core/helpers.js +212 -0
- package/eventState/030-todo-app-with-eventTest/runtime/core/router.js +271 -0
- package/eventState/030-todo-app-with-eventTest/store.d.ts +18 -0
- package/eventState/030-todo-app-with-eventTest/style.css +170 -0
- package/eventState/030-todo-app-with-eventTest/tests/README.md +208 -0
- package/eventState/030-todo-app-with-eventTest/tests/eventTest.js +176 -0
- package/eventState/030-todo-app-with-eventTest/tests/generateTypes.js +189 -0
- package/eventState/030-todo-app-with-eventTest/tests/run.js +20 -0
- package/eventState/030-todo-app-with-eventTest/tests/todos.test.js +167 -0
- package/eventState/031-todo-app-with-eventTest/LICENSE +55 -0
- package/eventState/031-todo-app-with-eventTest/README.md +54 -0
- package/eventState/031-todo-app-with-eventTest/TUTORIAL.md +390 -0
- package/eventState/031-todo-app-with-eventTest/WHY_EVENTSTATE.md +777 -0
- package/eventState/031-todo-app-with-eventTest/app/bridges.js +113 -0
- package/eventState/031-todo-app-with-eventTest/app/router.js +26 -0
- package/eventState/031-todo-app-with-eventTest/app/store.js +15 -0
- package/eventState/031-todo-app-with-eventTest/app/views/home.js +46 -0
- package/eventState/031-todo-app-with-eventTest/app/views/todoDemo.js +69 -0
- package/eventState/031-todo-app-with-eventTest/devtools/dock.js +41 -0
- package/eventState/031-todo-app-with-eventTest/devtools/stateTracker.dock.js +10 -0
- package/eventState/031-todo-app-with-eventTest/devtools/stateTracker.js +246 -0
- package/eventState/031-todo-app-with-eventTest/devtools/telemetry.js +104 -0
- package/eventState/031-todo-app-with-eventTest/devtools/typeGenerator.js +339 -0
- package/eventState/031-todo-app-with-eventTest/index.html +103 -0
- package/eventState/031-todo-app-with-eventTest/package-lock.json +2184 -0
- package/eventState/031-todo-app-with-eventTest/package.json +24 -0
- package/eventState/031-todo-app-with-eventTest/runtime/core/behaviors.runtime.js +282 -0
- package/eventState/031-todo-app-with-eventTest/runtime/core/eventState.js +100 -0
- package/eventState/031-todo-app-with-eventTest/runtime/core/eventStateNew.js +149 -0
- package/eventState/031-todo-app-with-eventTest/runtime/core/helpers.js +212 -0
- package/eventState/031-todo-app-with-eventTest/runtime/core/router.js +271 -0
- package/eventState/031-todo-app-with-eventTest/runtime/extensions/boundary.js +36 -0
- package/eventState/031-todo-app-with-eventTest/runtime/extensions/converge.js +63 -0
- package/eventState/031-todo-app-with-eventTest/runtime/extensions/eventState.plus.js +210 -0
- package/eventState/031-todo-app-with-eventTest/runtime/extensions/hydrate.js +157 -0
- package/eventState/031-todo-app-with-eventTest/runtime/extensions/queryBinding.js +69 -0
- package/eventState/031-todo-app-with-eventTest/runtime/forms/computed.js +78 -0
- package/eventState/031-todo-app-with-eventTest/runtime/forms/meta.js +51 -0
- package/eventState/031-todo-app-with-eventTest/runtime/forms/submitWithBoundary.js +28 -0
- package/eventState/031-todo-app-with-eventTest/runtime/forms/validators.js +55 -0
- package/eventState/031-todo-app-with-eventTest/store.d.ts +23 -0
- package/eventState/031-todo-app-with-eventTest/style.css +170 -0
- package/eventState/031-todo-app-with-eventTest/tests/README.md +208 -0
- package/eventState/031-todo-app-with-eventTest/tests/eventTest.js +176 -0
- package/eventState/031-todo-app-with-eventTest/tests/generateTypes.js +191 -0
- package/eventState/031-todo-app-with-eventTest/tests/run.js +20 -0
- package/eventState/031-todo-app-with-eventTest/tests/todos.test.js +192 -0
- package/eventState/032-todo-app-with-eventTest/LICENSE +55 -0
- package/eventState/032-todo-app-with-eventTest/README.md +54 -0
- package/eventState/032-todo-app-with-eventTest/TUTORIAL.md +390 -0
- package/eventState/032-todo-app-with-eventTest/WHY_EVENTSTATE.md +777 -0
- package/eventState/032-todo-app-with-eventTest/app/actions/index.js +153 -0
- package/eventState/032-todo-app-with-eventTest/app/bridges.js +113 -0
- package/eventState/032-todo-app-with-eventTest/app/router.js +26 -0
- package/eventState/032-todo-app-with-eventTest/app/store.js +15 -0
- package/eventState/032-todo-app-with-eventTest/app/views/home.js +46 -0
- package/eventState/032-todo-app-with-eventTest/app/views/todoDemo.js +69 -0
- package/eventState/032-todo-app-with-eventTest/devtools/dock.js +41 -0
- package/eventState/032-todo-app-with-eventTest/devtools/stateTracker.dock.js +10 -0
- package/eventState/032-todo-app-with-eventTest/devtools/stateTracker.js +246 -0
- package/eventState/032-todo-app-with-eventTest/devtools/telemetry.js +104 -0
- package/eventState/032-todo-app-with-eventTest/devtools/typeGenerator.js +339 -0
- package/eventState/032-todo-app-with-eventTest/index.html +87 -0
- package/eventState/032-todo-app-with-eventTest/package-lock.json +2184 -0
- package/eventState/032-todo-app-with-eventTest/package.json +24 -0
- package/eventState/032-todo-app-with-eventTest/runtime/core/behaviors.runtime.js +282 -0
- package/eventState/032-todo-app-with-eventTest/runtime/core/eventState.js +100 -0
- package/eventState/032-todo-app-with-eventTest/runtime/core/eventStateNew.js +149 -0
- package/eventState/032-todo-app-with-eventTest/runtime/core/helpers.js +212 -0
- package/eventState/032-todo-app-with-eventTest/runtime/core/router.js +271 -0
- package/eventState/032-todo-app-with-eventTest/runtime/extensions/boundary.js +36 -0
- package/eventState/032-todo-app-with-eventTest/runtime/extensions/converge.js +63 -0
- package/eventState/032-todo-app-with-eventTest/runtime/extensions/eventState.plus.js +210 -0
- package/eventState/032-todo-app-with-eventTest/runtime/extensions/hydrate.js +157 -0
- package/eventState/032-todo-app-with-eventTest/runtime/extensions/queryBinding.js +69 -0
- package/eventState/032-todo-app-with-eventTest/runtime/forms/computed.js +78 -0
- package/eventState/032-todo-app-with-eventTest/runtime/forms/meta.js +51 -0
- package/eventState/032-todo-app-with-eventTest/runtime/forms/submitWithBoundary.js +28 -0
- package/eventState/032-todo-app-with-eventTest/runtime/forms/validators.js +55 -0
- package/eventState/032-todo-app-with-eventTest/store.d.ts +23 -0
- package/eventState/032-todo-app-with-eventTest/style.css +170 -0
- package/eventState/032-todo-app-with-eventTest/tests/README.md +208 -0
- package/eventState/032-todo-app-with-eventTest/tests/eventTest.js +176 -0
- package/eventState/032-todo-app-with-eventTest/tests/generateTypes.js +191 -0
- package/eventState/032-todo-app-with-eventTest/tests/run.js +20 -0
- package/eventState/032-todo-app-with-eventTest/tests/todos.test.js +192 -0
- package/package.json +27 -0
|
@@ -0,0 +1,390 @@
|
|
|
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.*
|