@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.
- package/package.json +5 -5
- package/queryClient.js +55 -0
- package/examples/001-counter/README.md +0 -44
- package/examples/001-counter/index.html +0 -33
- package/examples/002-counter-improved/README.md +0 -44
- package/examples/002-counter-improved/index.html +0 -47
- package/examples/003-input-reactive/README.md +0 -44
- package/examples/003-input-reactive/index.html +0 -33
- package/examples/004-computed-state/README.md +0 -45
- package/examples/004-computed-state/index.html +0 -65
- package/examples/005-conditional-rendering/README.md +0 -42
- package/examples/005-conditional-rendering/index.html +0 -39
- package/examples/006-list-rendering/README.md +0 -49
- package/examples/006-list-rendering/index.html +0 -63
- package/examples/007-form-validation/README.md +0 -52
- package/examples/007-form-validation/index.html +0 -102
- package/examples/008-undo-redo/README.md +0 -70
- package/examples/008-undo-redo/index.html +0 -108
- package/examples/009-localStorage-side-effects/README.md +0 -72
- package/examples/009-localStorage-side-effects/index.html +0 -57
- package/examples/010-decoupled-components/README.md +0 -74
- package/examples/010-decoupled-components/index.html +0 -93
- package/examples/011-async-patterns/README.md +0 -98
- package/examples/011-async-patterns/index.html +0 -132
- package/examples/028-counter-improved-eventTest/LICENSE +0 -55
- package/examples/028-counter-improved-eventTest/README.md +0 -131
- package/examples/028-counter-improved-eventTest/app/store.js +0 -9
- package/examples/028-counter-improved-eventTest/index.html +0 -49
- package/examples/028-counter-improved-eventTest/runtime/core/behaviors.runtime.js +0 -282
- package/examples/028-counter-improved-eventTest/runtime/core/eventState.js +0 -100
- package/examples/028-counter-improved-eventTest/runtime/core/eventStateNew.js +0 -149
- package/examples/028-counter-improved-eventTest/runtime/core/helpers.js +0 -212
- package/examples/028-counter-improved-eventTest/runtime/core/router.js +0 -271
- package/examples/028-counter-improved-eventTest/store.d.ts +0 -8
- package/examples/028-counter-improved-eventTest/style.css +0 -170
- package/examples/028-counter-improved-eventTest/tests/README.md +0 -208
- package/examples/028-counter-improved-eventTest/tests/counter.test.js +0 -116
- package/examples/028-counter-improved-eventTest/tests/eventTest.js +0 -176
- package/examples/028-counter-improved-eventTest/tests/generateTypes.js +0 -168
- package/examples/028-counter-improved-eventTest/tests/run.js +0 -20
- package/examples/030-todo-app-with-eventTest/LICENSE +0 -55
- package/examples/030-todo-app-with-eventTest/README.md +0 -121
- package/examples/030-todo-app-with-eventTest/app/router.js +0 -25
- package/examples/030-todo-app-with-eventTest/app/store.js +0 -16
- package/examples/030-todo-app-with-eventTest/app/views/home.js +0 -11
- package/examples/030-todo-app-with-eventTest/app/views/todoDemo.js +0 -88
- package/examples/030-todo-app-with-eventTest/index.html +0 -65
- package/examples/030-todo-app-with-eventTest/runtime/core/behaviors.runtime.js +0 -282
- package/examples/030-todo-app-with-eventTest/runtime/core/eventState.js +0 -100
- package/examples/030-todo-app-with-eventTest/runtime/core/eventStateNew.js +0 -149
- package/examples/030-todo-app-with-eventTest/runtime/core/helpers.js +0 -212
- package/examples/030-todo-app-with-eventTest/runtime/core/router.js +0 -271
- package/examples/030-todo-app-with-eventTest/store.d.ts +0 -18
- package/examples/030-todo-app-with-eventTest/style.css +0 -170
- package/examples/030-todo-app-with-eventTest/tests/README.md +0 -208
- package/examples/030-todo-app-with-eventTest/tests/eventTest.js +0 -176
- package/examples/030-todo-app-with-eventTest/tests/generateTypes.js +0 -189
- package/examples/030-todo-app-with-eventTest/tests/run.js +0 -20
- package/examples/030-todo-app-with-eventTest/tests/todos.test.js +0 -167
- package/examples/031-todo-app-with-eventTest/LICENSE +0 -55
- package/examples/031-todo-app-with-eventTest/README.md +0 -54
- package/examples/031-todo-app-with-eventTest/TUTORIAL.md +0 -390
- package/examples/031-todo-app-with-eventTest/WHY_EVENTSTATE.md +0 -777
- package/examples/031-todo-app-with-eventTest/app/bridges.js +0 -113
- package/examples/031-todo-app-with-eventTest/app/router.js +0 -26
- package/examples/031-todo-app-with-eventTest/app/store.js +0 -15
- package/examples/031-todo-app-with-eventTest/app/views/home.js +0 -46
- package/examples/031-todo-app-with-eventTest/app/views/todoDemo.js +0 -69
- package/examples/031-todo-app-with-eventTest/devtools/dock.js +0 -41
- package/examples/031-todo-app-with-eventTest/devtools/stateTracker.dock.js +0 -10
- package/examples/031-todo-app-with-eventTest/devtools/stateTracker.js +0 -246
- package/examples/031-todo-app-with-eventTest/devtools/telemetry.js +0 -104
- package/examples/031-todo-app-with-eventTest/devtools/typeGenerator.js +0 -339
- package/examples/031-todo-app-with-eventTest/index.html +0 -103
- package/examples/031-todo-app-with-eventTest/package-lock.json +0 -2184
- package/examples/031-todo-app-with-eventTest/package.json +0 -24
- package/examples/031-todo-app-with-eventTest/runtime/core/behaviors.runtime.js +0 -282
- package/examples/031-todo-app-with-eventTest/runtime/core/eventState.js +0 -100
- package/examples/031-todo-app-with-eventTest/runtime/core/eventStateNew.js +0 -149
- package/examples/031-todo-app-with-eventTest/runtime/core/helpers.js +0 -212
- package/examples/031-todo-app-with-eventTest/runtime/core/router.js +0 -271
- package/examples/031-todo-app-with-eventTest/runtime/extensions/boundary.js +0 -36
- package/examples/031-todo-app-with-eventTest/runtime/extensions/converge.js +0 -63
- package/examples/031-todo-app-with-eventTest/runtime/extensions/eventState.plus.js +0 -210
- package/examples/031-todo-app-with-eventTest/runtime/extensions/hydrate.js +0 -157
- package/examples/031-todo-app-with-eventTest/runtime/extensions/queryBinding.js +0 -69
- package/examples/031-todo-app-with-eventTest/runtime/forms/computed.js +0 -78
- package/examples/031-todo-app-with-eventTest/runtime/forms/meta.js +0 -51
- package/examples/031-todo-app-with-eventTest/runtime/forms/submitWithBoundary.js +0 -28
- package/examples/031-todo-app-with-eventTest/runtime/forms/validators.js +0 -55
- package/examples/031-todo-app-with-eventTest/store.d.ts +0 -23
- package/examples/031-todo-app-with-eventTest/style.css +0 -170
- package/examples/031-todo-app-with-eventTest/tests/README.md +0 -208
- package/examples/031-todo-app-with-eventTest/tests/eventTest.js +0 -176
- package/examples/031-todo-app-with-eventTest/tests/generateTypes.js +0 -191
- package/examples/031-todo-app-with-eventTest/tests/run.js +0 -20
- package/examples/031-todo-app-with-eventTest/tests/todos.test.js +0 -192
- package/examples/032-todo-app-with-eventTest/LICENSE +0 -55
- package/examples/032-todo-app-with-eventTest/README.md +0 -54
- package/examples/032-todo-app-with-eventTest/TUTORIAL.md +0 -390
- package/examples/032-todo-app-with-eventTest/WHY_EVENTSTATE.md +0 -777
- package/examples/032-todo-app-with-eventTest/app/actions/index.js +0 -153
- package/examples/032-todo-app-with-eventTest/app/bridges.js +0 -113
- package/examples/032-todo-app-with-eventTest/app/router.js +0 -26
- package/examples/032-todo-app-with-eventTest/app/store.js +0 -15
- package/examples/032-todo-app-with-eventTest/app/views/home.js +0 -46
- package/examples/032-todo-app-with-eventTest/app/views/todoDemo.js +0 -69
- package/examples/032-todo-app-with-eventTest/devtools/dock.js +0 -41
- package/examples/032-todo-app-with-eventTest/devtools/stateTracker.dock.js +0 -10
- package/examples/032-todo-app-with-eventTest/devtools/stateTracker.js +0 -246
- package/examples/032-todo-app-with-eventTest/devtools/telemetry.js +0 -104
- package/examples/032-todo-app-with-eventTest/devtools/typeGenerator.js +0 -339
- package/examples/032-todo-app-with-eventTest/index.html +0 -87
- package/examples/032-todo-app-with-eventTest/package-lock.json +0 -2184
- package/examples/032-todo-app-with-eventTest/package.json +0 -24
- package/examples/032-todo-app-with-eventTest/runtime/core/behaviors.runtime.js +0 -282
- package/examples/032-todo-app-with-eventTest/runtime/core/eventState.js +0 -100
- package/examples/032-todo-app-with-eventTest/runtime/core/eventStateNew.js +0 -149
- package/examples/032-todo-app-with-eventTest/runtime/core/helpers.js +0 -212
- package/examples/032-todo-app-with-eventTest/runtime/core/router.js +0 -271
- package/examples/032-todo-app-with-eventTest/runtime/extensions/boundary.js +0 -36
- package/examples/032-todo-app-with-eventTest/runtime/extensions/converge.js +0 -63
- package/examples/032-todo-app-with-eventTest/runtime/extensions/eventState.plus.js +0 -210
- package/examples/032-todo-app-with-eventTest/runtime/extensions/hydrate.js +0 -157
- package/examples/032-todo-app-with-eventTest/runtime/extensions/queryBinding.js +0 -69
- package/examples/032-todo-app-with-eventTest/runtime/forms/computed.js +0 -78
- package/examples/032-todo-app-with-eventTest/runtime/forms/meta.js +0 -51
- package/examples/032-todo-app-with-eventTest/runtime/forms/submitWithBoundary.js +0 -28
- package/examples/032-todo-app-with-eventTest/runtime/forms/validators.js +0 -55
- package/examples/032-todo-app-with-eventTest/store.d.ts +0 -23
- package/examples/032-todo-app-with-eventTest/style.css +0 -170
- package/examples/032-todo-app-with-eventTest/tests/README.md +0 -208
- package/examples/032-todo-app-with-eventTest/tests/eventTest.js +0 -176
- package/examples/032-todo-app-with-eventTest/tests/generateTypes.js +0 -191
- package/examples/032-todo-app-with-eventTest/tests/run.js +0 -20
- package/examples/032-todo-app-with-eventTest/tests/todos.test.js +0 -192
- package/playground/exercise001.html +0 -38
- package/playground/exercise002.html +0 -49
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@uistate/core",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.3.0",
|
|
4
4
|
"description": "Lightweight event-driven state management with slot orchestration and experimental event-sequence testing (eventTest.js available under dual license)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.js",
|
|
@@ -10,7 +10,8 @@
|
|
|
10
10
|
"./eventStateNew": "./eventStateNew.js",
|
|
11
11
|
"./cssState": "./cssState.js",
|
|
12
12
|
"./stateSerializer": "./stateSerializer.js",
|
|
13
|
-
"./templateManager": "./templateManager.js"
|
|
13
|
+
"./templateManager": "./templateManager.js",
|
|
14
|
+
"./query": "./queryClient.js"
|
|
14
15
|
},
|
|
15
16
|
"files": [
|
|
16
17
|
"index.js",
|
|
@@ -19,11 +20,10 @@
|
|
|
19
20
|
"cssState.js",
|
|
20
21
|
"stateSerializer.js",
|
|
21
22
|
"templateManager.js",
|
|
23
|
+
"queryClient.js",
|
|
22
24
|
"eventTest.js",
|
|
23
25
|
"LICENSE",
|
|
24
|
-
"LICENSE-eventTest.md"
|
|
25
|
-
"examples/",
|
|
26
|
-
"playground/"
|
|
26
|
+
"LICENSE-eventTest.md"
|
|
27
27
|
],
|
|
28
28
|
"keywords": [
|
|
29
29
|
"state-management",
|
package/queryClient.js
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
// Mini QueryClient wrapper for EventState
|
|
2
|
+
// Thin async layer with standard query patterns
|
|
3
|
+
|
|
4
|
+
export const createQueryClient = (store) => {
|
|
5
|
+
return {
|
|
6
|
+
// Run a query with async state handling
|
|
7
|
+
async query(key, fetcher) {
|
|
8
|
+
return await store.setAsync(`query.${key}`, fetcher);
|
|
9
|
+
},
|
|
10
|
+
|
|
11
|
+
// Subscribe to query data
|
|
12
|
+
subscribe(key, cb) {
|
|
13
|
+
return store.subscribe(`query.${key}.data`, cb);
|
|
14
|
+
},
|
|
15
|
+
|
|
16
|
+
// Subscribe to query status
|
|
17
|
+
subscribeToStatus(key, cb) {
|
|
18
|
+
return store.subscribe(`query.${key}.status`, cb);
|
|
19
|
+
},
|
|
20
|
+
|
|
21
|
+
// Subscribe to query errors
|
|
22
|
+
|
|
23
|
+
subscribeToError(key, cb) {
|
|
24
|
+
return store.subscribe(`query.${key}.error`, cb);
|
|
25
|
+
},
|
|
26
|
+
|
|
27
|
+
// Read current query data
|
|
28
|
+
getData(key) {
|
|
29
|
+
return store.get(`query.${key}.data`);
|
|
30
|
+
},
|
|
31
|
+
|
|
32
|
+
// Read current query status
|
|
33
|
+
getStatus(key) {
|
|
34
|
+
return store.get(`query.${key}.status`);
|
|
35
|
+
},
|
|
36
|
+
|
|
37
|
+
// Read current query error
|
|
38
|
+
getError(key) {
|
|
39
|
+
return store.get(`query.${key}.error`);
|
|
40
|
+
},
|
|
41
|
+
|
|
42
|
+
// Cancel active query
|
|
43
|
+
cancel(key) {
|
|
44
|
+
store.cancel(`query.${key}`);
|
|
45
|
+
},
|
|
46
|
+
|
|
47
|
+
// Reset query to idle
|
|
48
|
+
invalidate(key) {
|
|
49
|
+
const p = `query.${key}`;
|
|
50
|
+
store.set(`${p}.data`, null);
|
|
51
|
+
store.set(`${p}.status`, "idle");
|
|
52
|
+
store.set(`${p}.error`, null);
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
};
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
# 001 Counter - Minimal EventState Example
|
|
2
|
-
|
|
3
|
-
The simplest possible EventState example: a counter with one button.
|
|
4
|
-
|
|
5
|
-
## What's Here
|
|
6
|
-
|
|
7
|
-
- `eventState.js` - ~60 lines of reactive state management
|
|
8
|
-
- `index.html` - Counter UI with subscription
|
|
9
|
-
|
|
10
|
-
## How It Works
|
|
11
|
-
|
|
12
|
-
```javascript
|
|
13
|
-
// 1. Create store
|
|
14
|
-
const store = createEventState({ count: 0 });
|
|
15
|
-
|
|
16
|
-
// 2. Subscribe to changes
|
|
17
|
-
store.subscribe('count', ({ value }) => {
|
|
18
|
-
document.getElementById('count').textContent = value;
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
// 3. Update state
|
|
22
|
-
store.set('count', store.get('count') + 1);
|
|
23
|
-
```
|
|
24
|
-
|
|
25
|
-
That's it. No framework, no build step, just reactive data.
|
|
26
|
-
|
|
27
|
-
## Run It
|
|
28
|
-
|
|
29
|
-
Open `index.html` in a browser. Click the `+` button to increment.
|
|
30
|
-
|
|
31
|
-
## Key Concepts
|
|
32
|
-
|
|
33
|
-
- **`createEventState(initial)`** - Creates a reactive store
|
|
34
|
-
- **`store.get(path)`** - Read state at dot-path
|
|
35
|
-
- **`store.set(path, value)`** - Write state and notify subscribers
|
|
36
|
-
- **`store.subscribe(path, handler)`** - React to changes
|
|
37
|
-
|
|
38
|
-
## Next Steps
|
|
39
|
-
|
|
40
|
-
See `examples/009-todo-app-with-eventTest/` for a full application with:
|
|
41
|
-
- Router
|
|
42
|
-
- Bridges (intent → domain pattern)
|
|
43
|
-
- Tests with type generation
|
|
44
|
-
- Dev tools
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
<html lang="en">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="UTF-8">
|
|
5
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
-
<title>001 Counter - EventState</title>
|
|
7
|
-
<script type="importmap">
|
|
8
|
-
{ "imports": { "@uistate/core": "../../index.js" } }
|
|
9
|
-
</script>
|
|
10
|
-
</head>
|
|
11
|
-
<body>
|
|
12
|
-
<h1>Counter: <span id="count">0</span></h1>
|
|
13
|
-
<button id="increment">+</button>
|
|
14
|
-
|
|
15
|
-
<script type="module">
|
|
16
|
-
import { createEventState } from '@uistate/core';
|
|
17
|
-
|
|
18
|
-
// Create store
|
|
19
|
-
const store = createEventState({ count: 0 });
|
|
20
|
-
|
|
21
|
-
// Subscribe to count changes
|
|
22
|
-
store.subscribe('count', ( value ) => {
|
|
23
|
-
document.getElementById('count').textContent = value;
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
// Increment on button click
|
|
27
|
-
document.getElementById('increment').onclick = () => {
|
|
28
|
-
const current = store.get('count');
|
|
29
|
-
store.set('count', current + 1);
|
|
30
|
-
};
|
|
31
|
-
</script>
|
|
32
|
-
</body>
|
|
33
|
-
</html>
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
# 001 Counter - Minimal EventState Example
|
|
2
|
-
|
|
3
|
-
The simplest possible EventState example: a counter with one button.
|
|
4
|
-
|
|
5
|
-
## What's Here
|
|
6
|
-
|
|
7
|
-
- `eventState.js` - ~60 lines of reactive state management
|
|
8
|
-
- `index.html` - Counter UI with subscription
|
|
9
|
-
|
|
10
|
-
## How It Works
|
|
11
|
-
|
|
12
|
-
```javascript
|
|
13
|
-
// 1. Create store
|
|
14
|
-
const store = createEventState({ count: 0 });
|
|
15
|
-
|
|
16
|
-
// 2. Subscribe to changes
|
|
17
|
-
store.subscribe('count', ({ value }) => {
|
|
18
|
-
document.getElementById('count').textContent = value;
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
// 3. Update state
|
|
22
|
-
store.set('count', store.get('count') + 1);
|
|
23
|
-
```
|
|
24
|
-
|
|
25
|
-
That's it. No framework, no build step, just reactive data.
|
|
26
|
-
|
|
27
|
-
## Run It
|
|
28
|
-
|
|
29
|
-
Open `index.html` in a browser. Click the `+` button to increment.
|
|
30
|
-
|
|
31
|
-
## Key Concepts
|
|
32
|
-
|
|
33
|
-
- **`createEventState(initial)`** - Creates a reactive store
|
|
34
|
-
- **`store.get(path)`** - Read state at dot-path
|
|
35
|
-
- **`store.set(path, value)`** - Write state and notify subscribers
|
|
36
|
-
- **`store.subscribe(path, handler)`** - React to changes
|
|
37
|
-
|
|
38
|
-
## Next Steps
|
|
39
|
-
|
|
40
|
-
See `examples/009-todo-app-with-eventTest/` for a full application with:
|
|
41
|
-
- Router
|
|
42
|
-
- Bridges (intent → domain pattern)
|
|
43
|
-
- Tests with type generation
|
|
44
|
-
- Dev tools
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
<html lang="en">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="UTF-8">
|
|
5
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
-
<title>002 Counter Improved - EventState</title>
|
|
7
|
-
<script type="importmap">
|
|
8
|
-
{ "imports": { "@uistate/core": "../../index.js" } }
|
|
9
|
-
</script>
|
|
10
|
-
</head>
|
|
11
|
-
<body>
|
|
12
|
-
<h1>Counter: <span id="count">0</span></h1>
|
|
13
|
-
<button id="increment">+</button>
|
|
14
|
-
<button id="decrement">-</button>
|
|
15
|
-
<button id="double">x2</button>
|
|
16
|
-
|
|
17
|
-
<script type="module">
|
|
18
|
-
import { createEventState } from '@uistate/core';
|
|
19
|
-
|
|
20
|
-
// Create store
|
|
21
|
-
const store = createEventState({ count: 0 });
|
|
22
|
-
|
|
23
|
-
// Subscribe to count changes
|
|
24
|
-
store.subscribe('count', ( value ) => {
|
|
25
|
-
document.getElementById('count').textContent = value;
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
// Increment on button click
|
|
29
|
-
document.getElementById('increment').onclick = () => {
|
|
30
|
-
const current = store.get('count');
|
|
31
|
-
store.set('count', current + 1);
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
// Decrement on button click
|
|
35
|
-
document.getElementById('decrement').onclick = () => {
|
|
36
|
-
const current = store.get('count');
|
|
37
|
-
store.set('count', current - 1);
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
// Decrement on button click
|
|
41
|
-
document.getElementById('double').onclick = () => {
|
|
42
|
-
const current = store.get('count');
|
|
43
|
-
store.set('count', current * 2);
|
|
44
|
-
};
|
|
45
|
-
</script>
|
|
46
|
-
</body>
|
|
47
|
-
</html>
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
# 001 Counter - Minimal EventState Example
|
|
2
|
-
|
|
3
|
-
The simplest possible EventState example: a counter with one button.
|
|
4
|
-
|
|
5
|
-
## What's Here
|
|
6
|
-
|
|
7
|
-
- `eventState.js` - ~60 lines of reactive state management
|
|
8
|
-
- `index.html` - Counter UI with subscription
|
|
9
|
-
|
|
10
|
-
## How It Works
|
|
11
|
-
|
|
12
|
-
```javascript
|
|
13
|
-
// 1. Create store
|
|
14
|
-
const store = createEventState({ count: 0 });
|
|
15
|
-
|
|
16
|
-
// 2. Subscribe to changes
|
|
17
|
-
store.subscribe('count', ({ value }) => {
|
|
18
|
-
document.getElementById('count').textContent = value;
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
// 3. Update state
|
|
22
|
-
store.set('count', store.get('count') + 1);
|
|
23
|
-
```
|
|
24
|
-
|
|
25
|
-
That's it. No framework, no build step, just reactive data.
|
|
26
|
-
|
|
27
|
-
## Run It
|
|
28
|
-
|
|
29
|
-
Open `index.html` in a browser. Click the `+` button to increment.
|
|
30
|
-
|
|
31
|
-
## Key Concepts
|
|
32
|
-
|
|
33
|
-
- **`createEventState(initial)`** - Creates a reactive store
|
|
34
|
-
- **`store.get(path)`** - Read state at dot-path
|
|
35
|
-
- **`store.set(path, value)`** - Write state and notify subscribers
|
|
36
|
-
- **`store.subscribe(path, handler)`** - React to changes
|
|
37
|
-
|
|
38
|
-
## Next Steps
|
|
39
|
-
|
|
40
|
-
See `examples/009-todo-app-with-eventTest/` for a full application with:
|
|
41
|
-
- Router
|
|
42
|
-
- Bridges (intent → domain pattern)
|
|
43
|
-
- Tests with type generation
|
|
44
|
-
- Dev tools
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
<html lang="en">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="UTF-8">
|
|
5
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
-
<title>003 Input Reactive - EventState</title>
|
|
7
|
-
<script type="importmap">
|
|
8
|
-
{ "imports": { "@uistate/core": "../../index.js" } }
|
|
9
|
-
</script>
|
|
10
|
-
</head>
|
|
11
|
-
<body>
|
|
12
|
-
<h1>Type something:</h1>
|
|
13
|
-
<input type="text" id="textInput" placeholder="Start typing...">
|
|
14
|
-
<p id="output"></p>
|
|
15
|
-
|
|
16
|
-
<script type="module">
|
|
17
|
-
import { createEventState } from '@uistate/core';
|
|
18
|
-
|
|
19
|
-
// Create store
|
|
20
|
-
const store = createEventState({ text: '' });
|
|
21
|
-
|
|
22
|
-
// Subscribe to text changes
|
|
23
|
-
store.subscribe('text', (value) => {
|
|
24
|
-
document.getElementById('output').textContent = value;
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
// Update state on input
|
|
28
|
-
document.getElementById('textInput').oninput = (e) => {
|
|
29
|
-
store.set('text', e.target.value);
|
|
30
|
-
};
|
|
31
|
-
</script>
|
|
32
|
-
</body>
|
|
33
|
-
</html>
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
# 004 Computed State - Derived Values
|
|
2
|
-
|
|
3
|
-
Shows how trivial it is to create computed/derived state in EventState.
|
|
4
|
-
|
|
5
|
-
## What's Here
|
|
6
|
-
|
|
7
|
-
- Two inputs: `firstName` and `lastName`
|
|
8
|
-
- Two computed values: `fullName` and `charCount`
|
|
9
|
-
- **Zero framework magic** - just functions
|
|
10
|
-
|
|
11
|
-
## How It Works
|
|
12
|
-
|
|
13
|
-
```javascript
|
|
14
|
-
// 1. Define a function that computes derived state
|
|
15
|
-
const updateFullName = () => {
|
|
16
|
-
const first = store.get('firstName');
|
|
17
|
-
const last = store.get('lastName');
|
|
18
|
-
const fullName = `${first} ${last}`.trim();
|
|
19
|
-
document.getElementById('fullName').textContent = fullName;
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
// 2. Subscribe to wildcard to catch all changes
|
|
23
|
-
store.subscribe('*', () => {
|
|
24
|
-
updateFullName();
|
|
25
|
-
updateCharCount();
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
// 3. That's it. No special API needed.
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
## Key Insight
|
|
32
|
-
|
|
33
|
-
**Computed state is just a function.**
|
|
34
|
-
|
|
35
|
-
Other frameworks need:
|
|
36
|
-
- Vue: `computed()`
|
|
37
|
-
- React: `useMemo()`
|
|
38
|
-
- Svelte: `$:` reactive declarations
|
|
39
|
-
- MobX: `@computed` decorators
|
|
40
|
-
|
|
41
|
-
**EventState:** Just write a function and call it when state changes.
|
|
42
|
-
|
|
43
|
-
## Run It
|
|
44
|
-
|
|
45
|
-
Open `index.html` in a browser. Type in the inputs and watch the computed values update.
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
<html lang="en">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="UTF-8">
|
|
5
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
-
<title>004 Computed State - EventState</title>
|
|
7
|
-
<script type="importmap">
|
|
8
|
-
{ "imports": { "@uistate/core": "../../index.js" } }
|
|
9
|
-
</script>
|
|
10
|
-
</head>
|
|
11
|
-
<body>
|
|
12
|
-
<h1>Computed State</h1>
|
|
13
|
-
|
|
14
|
-
<label>First Name: <input type="text" id="firstName" placeholder="Abraham"></label><br>
|
|
15
|
-
<label>Last Name: <input type="text" id="lastName" placeholder="Lincoln"></label><br>
|
|
16
|
-
|
|
17
|
-
<p><strong>Full Name:</strong> <span id="fullName"></span></p>
|
|
18
|
-
<p><strong>Character Count:</strong> <span id="charCount">0</span></p>
|
|
19
|
-
|
|
20
|
-
<script type="module">
|
|
21
|
-
import { createEventState } from '@uistate/core';
|
|
22
|
-
|
|
23
|
-
// Create store
|
|
24
|
-
const store = createEventState({
|
|
25
|
-
firstName: '',
|
|
26
|
-
lastName: ''
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
// Computed: full name (derived from firstName + lastName)
|
|
30
|
-
const updateFullName = () => {
|
|
31
|
-
const first = store.get('firstName');
|
|
32
|
-
const last = store.get('lastName');
|
|
33
|
-
const fullName = `${first} ${last}`.trim();
|
|
34
|
-
document.getElementById('fullName').textContent = fullName || '(empty)';
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
// Computed: character count
|
|
38
|
-
const updateCharCount = () => {
|
|
39
|
-
const first = store.get('firstName');
|
|
40
|
-
const last = store.get('lastName');
|
|
41
|
-
const total = (first + last).length;
|
|
42
|
-
document.getElementById('charCount').textContent = total;
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
// Subscribe to any state change and recompute
|
|
46
|
-
store.subscribe('*', () => {
|
|
47
|
-
updateFullName();
|
|
48
|
-
updateCharCount();
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
// Wire up inputs
|
|
52
|
-
document.getElementById('firstName').oninput = (e) => {
|
|
53
|
-
store.set('firstName', e.target.value);
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
document.getElementById('lastName').oninput = (e) => {
|
|
57
|
-
store.set('lastName', e.target.value);
|
|
58
|
-
};
|
|
59
|
-
|
|
60
|
-
// Initial render
|
|
61
|
-
updateFullName();
|
|
62
|
-
updateCharCount();
|
|
63
|
-
</script>
|
|
64
|
-
</body>
|
|
65
|
-
</html>
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
# 005 Conditional Rendering - Show/Hide Elements
|
|
2
|
-
|
|
3
|
-
Demonstrates how to conditionally render elements based on state.
|
|
4
|
-
|
|
5
|
-
## What's Here
|
|
6
|
-
|
|
7
|
-
- Checkbox to toggle visibility
|
|
8
|
-
- Message that shows/hides based on state
|
|
9
|
-
- **No `v-if` or `{#if}` needed** - just DOM manipulation
|
|
10
|
-
|
|
11
|
-
## How It Works
|
|
12
|
-
|
|
13
|
-
```javascript
|
|
14
|
-
// 1. Store boolean state
|
|
15
|
-
const store = createEventState({ isVisible: false });
|
|
16
|
-
|
|
17
|
-
// 2. Subscribe and toggle display
|
|
18
|
-
store.subscribe('isVisible', (value) => {
|
|
19
|
-
const message = document.getElementById('message');
|
|
20
|
-
message.style.display = value ? 'block' : 'none';
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
// 3. Update state on checkbox change
|
|
24
|
-
document.getElementById('toggle').onchange = (e) => {
|
|
25
|
-
store.set('isVisible', e.target.checked);
|
|
26
|
-
};
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
## Key Insight
|
|
30
|
-
|
|
31
|
-
**Conditional rendering is just DOM manipulation.**
|
|
32
|
-
|
|
33
|
-
Other frameworks need:
|
|
34
|
-
- React: `{isVisible && <p>Message</p>}`
|
|
35
|
-
- Vue: `v-if="isVisible"`
|
|
36
|
-
- Svelte: `{#if isVisible}`
|
|
37
|
-
|
|
38
|
-
**EventState:** Just set `style.display` in a subscriber. That's it.
|
|
39
|
-
|
|
40
|
-
## Run It
|
|
41
|
-
|
|
42
|
-
Open `index.html` in a browser. Check the box to reveal the message.
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
<html lang="en">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="UTF-8">
|
|
5
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
-
<title>005 Conditional Rendering - EventState</title>
|
|
7
|
-
<script type="importmap">
|
|
8
|
-
{ "imports": { "@uistate/core": "../../index.js" } }
|
|
9
|
-
</script>
|
|
10
|
-
</head>
|
|
11
|
-
<body>
|
|
12
|
-
<h1>Conditional Rendering</h1>
|
|
13
|
-
|
|
14
|
-
<label>
|
|
15
|
-
<input type="checkbox" id="toggle">
|
|
16
|
-
Show secret message
|
|
17
|
-
</label>
|
|
18
|
-
|
|
19
|
-
<p id="message" style="display: none;">You found the secret message!</p>
|
|
20
|
-
|
|
21
|
-
<script type="module">
|
|
22
|
-
import { createEventState } from '@uistate/core';
|
|
23
|
-
|
|
24
|
-
// Create store
|
|
25
|
-
const store = createEventState({ isVisible: false });
|
|
26
|
-
|
|
27
|
-
// Subscribe to visibility changes
|
|
28
|
-
store.subscribe('isVisible', (value) => {
|
|
29
|
-
const message = document.getElementById('message');
|
|
30
|
-
message.style.display = value ? 'block' : 'none';
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
// Toggle on checkbox change
|
|
34
|
-
document.getElementById('toggle').onchange = (e) => {
|
|
35
|
-
store.set('isVisible', e.target.checked);
|
|
36
|
-
};
|
|
37
|
-
</script>
|
|
38
|
-
</body>
|
|
39
|
-
</html>
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
# 006 List Rendering - Dynamic Arrays
|
|
2
|
-
|
|
3
|
-
Demonstrates how to render lists from array state.
|
|
4
|
-
|
|
5
|
-
## What's Here
|
|
6
|
-
|
|
7
|
-
- Input to add items
|
|
8
|
-
- Dynamic list that updates on state change
|
|
9
|
-
- **No `v-for` or `.map()` in JSX** - just `innerHTML`
|
|
10
|
-
|
|
11
|
-
## How It Works
|
|
12
|
-
|
|
13
|
-
```javascript
|
|
14
|
-
// 1. Store array in state
|
|
15
|
-
const store = createEventState({ items: [] });
|
|
16
|
-
|
|
17
|
-
// 2. Render function
|
|
18
|
-
const renderList = () => {
|
|
19
|
-
const items = store.get('items');
|
|
20
|
-
const list = document.getElementById('itemList');
|
|
21
|
-
list.innerHTML = items.map(item => `<li>${item}</li>`).join('');
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
// 3. Subscribe to array changes
|
|
25
|
-
store.subscribe('items', renderList);
|
|
26
|
-
|
|
27
|
-
// 4. Add items by creating new array
|
|
28
|
-
const items = store.get('items');
|
|
29
|
-
store.set('items', [...items, newItem]);
|
|
30
|
-
```
|
|
31
|
-
|
|
32
|
-
## Key Insight
|
|
33
|
-
|
|
34
|
-
**List rendering is just string concatenation.**
|
|
35
|
-
|
|
36
|
-
Other frameworks need:
|
|
37
|
-
- React: `{items.map(item => <li>{item}</li>)}`
|
|
38
|
-
- Vue: `v-for="item in items"`
|
|
39
|
-
- Svelte: `{#each items as item}`
|
|
40
|
-
|
|
41
|
-
**EventState:** Just use `.map()` and `innerHTML`. That's it.
|
|
42
|
-
|
|
43
|
-
## Important
|
|
44
|
-
|
|
45
|
-
We create a **new array** with `[...items, newItem]` instead of mutating. This ensures the subscription fires (new reference = change detected).
|
|
46
|
-
|
|
47
|
-
## Run It
|
|
48
|
-
|
|
49
|
-
Open `index.html` in a browser. Type items and click Add (or press Enter).
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
<html lang="en">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="UTF-8">
|
|
5
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
-
<title>006 List Rendering - EventState</title>
|
|
7
|
-
<script type="importmap">
|
|
8
|
-
{ "imports": { "@uistate/core": "../../index.js" } }
|
|
9
|
-
</script>
|
|
10
|
-
</head>
|
|
11
|
-
<body>
|
|
12
|
-
<h1>Shopping List</h1>
|
|
13
|
-
|
|
14
|
-
<input type="text" id="itemInput" placeholder="Add item...">
|
|
15
|
-
<button id="addBtn">Add</button>
|
|
16
|
-
|
|
17
|
-
<ul id="itemList"></ul>
|
|
18
|
-
|
|
19
|
-
<script type="module">
|
|
20
|
-
import { createEventState } from '@uistate/core';
|
|
21
|
-
|
|
22
|
-
// Create store
|
|
23
|
-
const store = createEventState({ items: [] });
|
|
24
|
-
|
|
25
|
-
// Render list
|
|
26
|
-
const renderList = () => {
|
|
27
|
-
const items = store.get('items');
|
|
28
|
-
const list = document.getElementById('itemList');
|
|
29
|
-
|
|
30
|
-
if (items.length === 0) {
|
|
31
|
-
list.innerHTML = '<li><em>No items yet</em></li>';
|
|
32
|
-
} else {
|
|
33
|
-
list.innerHTML = items.map(item => `<li>${item}</li>`).join('');
|
|
34
|
-
}
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
// Subscribe to items changes
|
|
38
|
-
store.subscribe('items', renderList);
|
|
39
|
-
|
|
40
|
-
// Add item
|
|
41
|
-
document.getElementById('addBtn').onclick = () => {
|
|
42
|
-
const input = document.getElementById('itemInput');
|
|
43
|
-
const value = input.value.trim();
|
|
44
|
-
|
|
45
|
-
if (value) {
|
|
46
|
-
const items = store.get('items');
|
|
47
|
-
store.set('items', [...items, value]);
|
|
48
|
-
input.value = '';
|
|
49
|
-
}
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
// Add on Enter key
|
|
53
|
-
document.getElementById('itemInput').onkeypress = (e) => {
|
|
54
|
-
if (e.key === 'Enter') {
|
|
55
|
-
document.getElementById('addBtn').click();
|
|
56
|
-
}
|
|
57
|
-
};
|
|
58
|
-
|
|
59
|
-
// Initial render
|
|
60
|
-
renderList();
|
|
61
|
-
</script>
|
|
62
|
-
</body>
|
|
63
|
-
</html>
|