@everystate/examples 1.0.0 → 1.0.1
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 +15 -0
- package/everyState-core/001-counter/README.md +44 -0
- package/everyState-core/001-counter/index.html +79 -0
- package/everyState-core/002-counter-improved/README.md +44 -0
- package/everyState-core/002-counter-improved/index.html +83 -0
- package/everyState-core/003-input-reactive/README.md +44 -0
- package/everyState-core/003-input-reactive/index.html +68 -0
- package/everyState-core/004-computed-state/README.md +45 -0
- package/everyState-core/004-computed-state/index.html +83 -0
- package/everyState-core/005-conditional-rendering/README.md +42 -0
- package/everyState-core/005-conditional-rendering/index.html +68 -0
- package/everyState-core/006-list-rendering/README.md +49 -0
- package/everyState-core/006-list-rendering/index.html +92 -0
- package/everyState-core/007-form-validation/README.md +52 -0
- package/everyState-core/007-form-validation/index.html +108 -0
- package/everyState-core/008-undo-redo/README.md +70 -0
- package/everyState-core/008-undo-redo/index.html +133 -0
- package/everyState-core/009-localStorage-side-effects/README.md +72 -0
- package/everyState-core/009-localStorage-side-effects/index.html +80 -0
- package/everyState-core/010-decoupled-components/README.md +74 -0
- package/everyState-core/010-decoupled-components/index.html +117 -0
- package/everyState-core/011-async-patterns/README.md +98 -0
- package/everyState-core/011-async-patterns/index.html +132 -0
- package/everyState-css/001-stateDrivenCSS/index.html +377 -0
- package/everyState-css/002-cssV2FullDemo/index.html +630 -0
- package/everyState-view/001/counter/index.css +31 -0
- package/everyState-view/001/counter/index.html +50 -0
- package/everyState-view/002/datatable/index.css +70 -0
- package/everyState-view/002/datatable/index.html +118 -0
- package/everyState-view/003/todo/index.css +260 -0
- package/everyState-view/003/todo/index.html +218 -0
- package/everyState-view/003-input-reactive/README.md +44 -0
- package/everyState-view/003-input-reactive/index.html +68 -0
- package/everyState-view/004/quotesFetcher/index.css +124 -0
- package/everyState-view/004/quotesFetcher/index.html +108 -0
- package/everyState-view/004_01/quotesFetcher/app.js +32 -0
- package/everyState-view/004_01/quotesFetcher/components/appHeader/appSubtitle.js +2 -0
- package/everyState-view/004_01/quotesFetcher/components/appHeader/appTitle.js +2 -0
- package/everyState-view/004_01/quotesFetcher/components/appHeader.js +9 -0
- package/everyState-view/004_01/quotesFetcher/components/historyHeading.js +2 -0
- package/everyState-view/004_01/quotesFetcher/components/historyList/histAuthor.js +2 -0
- package/everyState-view/004_01/quotesFetcher/components/historyList/histQuote.js +2 -0
- package/everyState-view/004_01/quotesFetcher/components/historyList.js +14 -0
- package/everyState-view/004_01/quotesFetcher/components/quoteCard/fetchButton.js +2 -0
- package/everyState-view/004_01/quotesFetcher/components/quoteCard/quoteAuthor.js +2 -0
- package/everyState-view/004_01/quotesFetcher/components/quoteCard/quoteMessage.js +2 -0
- package/everyState-view/004_01/quotesFetcher/components/quoteCard/quoteText.js +2 -0
- package/everyState-view/004_01/quotesFetcher/components/quoteCard.js +11 -0
- package/everyState-view/004_01/quotesFetcher/index.css +124 -0
- package/everyState-view/004_01/quotesFetcher/index.html +23 -0
- package/everyState-view/004_01/quotesFetcher/store.js +35 -0
- package/everyState-view/004_02/quotesFetcher/app.js +20 -0
- package/everyState-view/004_02/quotesFetcher/components.js +46 -0
- package/everyState-view/004_02/quotesFetcher/index.css +124 -0
- package/everyState-view/004_02/quotesFetcher/index.html +23 -0
- package/everyState-view/004_02/quotesFetcher/store.js +35 -0
- package/everyState-view/004_03/quotesFetcher/actions.js +27 -0
- package/everyState-view/004_03/quotesFetcher/app.js +19 -0
- package/everyState-view/004_03/quotesFetcher/components.js +28 -0
- package/everyState-view/004_03/quotesFetcher/index.css +124 -0
- package/everyState-view/004_03/quotesFetcher/index.html +23 -0
- package/everyState-view/004_03/quotesFetcher/resolve.js +34 -0
- package/everyState-view/004_03/quotesFetcher/store.js +11 -0
- package/everyState-view/004_04/quotesFetcher/actions.js +66 -0
- package/everyState-view/004_04/quotesFetcher/app.js +24 -0
- package/everyState-view/004_04/quotesFetcher/components/archive.js +40 -0
- package/everyState-view/004_04/quotesFetcher/components/fetcher.js +29 -0
- package/everyState-view/004_04/quotesFetcher/components.js +20 -0
- package/everyState-view/004_04/quotesFetcher/index.css +283 -0
- package/everyState-view/004_04/quotesFetcher/index.html +24 -0
- package/everyState-view/004_04/quotesFetcher/resolve.js +34 -0
- package/everyState-view/004_04/quotesFetcher/store.js +21 -0
- package/everyState-view/004_04/statedump.json +826 -0
- package/everyState-view/004_05/quoteExplorer/actions.js +58 -0
- package/everyState-view/004_05/quoteExplorer/app.js +27 -0
- package/everyState-view/004_05/quoteExplorer/components.js +83 -0
- package/everyState-view/004_05/quoteExplorer/index.css +231 -0
- package/everyState-view/004_05/quoteExplorer/index.html +23 -0
- package/everyState-view/004_05/quoteExplorer/resolve.js +50 -0
- package/everyState-view/004_05/quoteExplorer/store.js +33 -0
- package/everyState-view/004_06/quoteExplorer/actions.js +21 -0
- package/everyState-view/004_06/quoteExplorer/app.js +44 -0
- package/everyState-view/004_06/quoteExplorer/components.js +80 -0
- package/everyState-view/004_06/quoteExplorer/derived.js +43 -0
- package/everyState-view/004_06/quoteExplorer/index.css +346 -0
- package/everyState-view/004_06/quoteExplorer/index.html +25 -0
- package/everyState-view/004_06/quoteExplorer/intents.js +44 -0
- package/everyState-view/004_06/quoteExplorer/policies.js +25 -0
- package/everyState-view/004_06/quoteExplorer/resolve.js +51 -0
- package/everyState-view/004_06/quoteExplorer/store.js +44 -0
- package/everyState-view/004_07/quoteExplorer/app.js +47 -0
- package/everyState-view/004_07/quoteExplorer/components.js +85 -0
- package/everyState-view/004_07/quoteExplorer/derived.js +43 -0
- package/everyState-view/004_07/quoteExplorer/index.css +346 -0
- package/everyState-view/004_07/quoteExplorer/index.html +25 -0
- package/everyState-view/004_07/quoteExplorer/intents.js +51 -0
- package/everyState-view/004_07/quoteExplorer/policies.js +21 -0
- package/everyState-view/004_07/quoteExplorer/resolve.js +39 -0
- package/everyState-view/004_07/quoteExplorer/store.js +44 -0
- package/everyState-view/004_08/quoteExplorer/app.js +78 -0
- package/everyState-view/004_08/quoteExplorer/components.js +85 -0
- package/everyState-view/004_08/quoteExplorer/derived.js +43 -0
- package/everyState-view/004_08/quoteExplorer/index.css +346 -0
- package/everyState-view/004_08/quoteExplorer/index.html +25 -0
- package/everyState-view/004_08/quoteExplorer/intents.js +51 -0
- package/everyState-view/004_08/quoteExplorer/policies.js +21 -0
- package/everyState-view/004_08/quoteExplorer/resolve.js +39 -0
- package/everyState-view/004_08/quoteExplorer/store.js +44 -0
- package/everyState-view/004_08_V2/app.js +78 -0
- package/everyState-view/004_08_V2/components/appDetail.js +8 -0
- package/everyState-view/004_08_V2/components/appDetailBar.js +7 -0
- package/everyState-view/004_08_V2/components/appDetailBarClose.js +8 -0
- package/everyState-view/004_08_V2/components/appDetailBarCount.js +7 -0
- package/everyState-view/004_08_V2/components/appDetailBarHeading.js +7 -0
- package/everyState-view/004_08_V2/components/appDetailQuotes.js +15 -0
- package/everyState-view/004_08_V2/components/appHeader.js +7 -0
- package/everyState-view/004_08_V2/components/appHeaderSubtitle.js +7 -0
- package/everyState-view/004_08_V2/components/appHeaderTitle.js +7 -0
- package/everyState-view/004_08_V2/components/appLog.js +7 -0
- package/everyState-view/004_08_V2/components/appLogHeading.js +7 -0
- package/everyState-view/004_08_V2/components/appLogList.js +16 -0
- package/everyState-view/004_08_V2/components/appSearch.js +7 -0
- package/everyState-view/004_08_V2/components/appSearchInput.js +9 -0
- package/everyState-view/004_08_V2/components/appStats.js +7 -0
- package/everyState-view/004_08_V2/components/appStatsContent.js +8 -0
- package/everyState-view/004_08_V2/components/appStatsContentFavcount.js +7 -0
- package/everyState-view/004_08_V2/components/appStatsContentText.js +7 -0
- package/everyState-view/004_08_V2/components/appStatsToggle.js +8 -0
- package/everyState-view/004_08_V2/components/appTags.js +7 -0
- package/everyState-view/004_08_V2/components/appTagsLabel.js +7 -0
- package/everyState-view/004_08_V2/components/appTagsRow.js +15 -0
- package/everyState-view/004_08_V2/components/index.js +59 -0
- package/everyState-view/004_08_V2/components/utils/css.js +88 -0
- package/everyState-view/004_08_V2/components/utils/elements.js +87 -0
- package/everyState-view/004_08_V2/components.js +79 -0
- package/everyState-view/004_08_V2/derived.js +43 -0
- package/everyState-view/004_08_V2/index.css +350 -0
- package/everyState-view/004_08_V2/index.html +25 -0
- package/everyState-view/004_08_V2/intents.js +51 -0
- package/everyState-view/004_08_V2/policies.js +21 -0
- package/everyState-view/004_08_V2/resolve.js +39 -0
- package/everyState-view/004_08_V2/store.js +44 -0
- package/everyState-view/006/api-datatable/index.css +388 -0
- package/everyState-view/006/api-datatable/index.html +355 -0
- package/everyState-view/007/apiUsers/index.html +307 -0
- package/everyState-view/007-form-validation/README.md +52 -0
- package/everyState-view/007-form-validation/index.html +108 -0
- package/everyState-view/010-decoupled-components/README.md +74 -0
- package/everyState-view/010-decoupled-components/index.html +117 -0
- package/everyState-view/index.html +36 -0
- package/index.js +0 -5
- package/package.json +2 -4
package/README.md
CHANGED
|
@@ -24,6 +24,21 @@ npm install @everystate/examples
|
|
|
24
24
|
|
|
25
25
|
Each example is a standalone HTML file that can be opened in a browser or served locally.
|
|
26
26
|
|
|
27
|
+
## Ecosystem
|
|
28
|
+
|
|
29
|
+
| Package | Description | License |
|
|
30
|
+
|---|---|---|
|
|
31
|
+
| [@everystate/aliases](https://www.npmjs.com/package/@everystate/aliases) | Ergonomic single-character and short-name DOM aliases for vanilla JS | MIT |
|
|
32
|
+
| [@everystate/core](https://www.npmjs.com/package/@everystate/core) | Path-based state management with wildcard subscriptions and async support. Core state engine (you are here). | MIT |
|
|
33
|
+
| [@everystate/css](https://www.npmjs.com/package/@everystate/css) | Reactive CSSOM engine: design tokens, typed validation, WCAG enforcement, all via path-based state | MIT |
|
|
34
|
+
| [@everystate/examples](https://www.npmjs.com/package/@everystate/examples) | Example applications and patterns | MIT |
|
|
35
|
+
| [@everystate/perf](https://www.npmjs.com/package/@everystate/perf) | Performance monitoring overlay | MIT |
|
|
36
|
+
| [@everystate/react](https://www.npmjs.com/package/@everystate/react) | React hooks adapter: `usePath`, `useIntent`, `useAsync` hooks and `EveryStateProvider` | MIT |
|
|
37
|
+
| [@everystate/renderer](https://www.npmjs.com/package/@everystate/renderer) | Direct-binding reactive renderer: `bind-*`, `set`, `each` attributes. Zero build step | Proprietary |
|
|
38
|
+
| [@everystate/router](https://www.npmjs.com/package/@everystate/router) | SPA routing as state | MIT |
|
|
39
|
+
| [@everystate/test](https://www.npmjs.com/package/@everystate/test) | Event-sequence testing for EveryState stores. Zero dependency. | Proprietary |
|
|
40
|
+
| [@everystate/view](https://www.npmjs.com/package/@everystate/view) | State-driven view: DOMless resolve + surgical DOM projector. View tree as first-class state | MIT |
|
|
41
|
+
|
|
27
42
|
## License
|
|
28
43
|
|
|
29
44
|
MIT © Ajdin Imsirovic
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# 001 Counter - Minimal EveryState Example
|
|
2
|
+
|
|
3
|
+
The simplest possible EveryState example: a counter with one button.
|
|
4
|
+
|
|
5
|
+
## What's Here
|
|
6
|
+
|
|
7
|
+
- `everyState.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 = createEveryState({ 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
|
+
- **`createEveryState(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
|
|
@@ -0,0 +1,79 @@
|
|
|
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 - EveryState</title>
|
|
7
|
+
<script type="importmap">
|
|
8
|
+
{ "imports": {
|
|
9
|
+
"@everystate/core": "../../../everystate-core/index.js",
|
|
10
|
+
"@everystate/aliases": "../../../everystate-aliases/index.js",
|
|
11
|
+
"@everystate/perf": "../../../everystate-perf/index.js"
|
|
12
|
+
}}
|
|
13
|
+
</script>
|
|
14
|
+
</head>
|
|
15
|
+
<body>
|
|
16
|
+
<h1>Counter: <span id="count">0</span></h1>
|
|
17
|
+
<button id="increment">+</button>
|
|
18
|
+
<hr>
|
|
19
|
+
<button id="runTests">Run Tests</button>
|
|
20
|
+
<pre id="testLog"></pre>
|
|
21
|
+
|
|
22
|
+
<script type="module">
|
|
23
|
+
import { createEveryState } from '@everystate/core';
|
|
24
|
+
import { $ } from '@everystate/aliases';
|
|
25
|
+
import { createPerfMonitor, mountOverlay } from '@everystate/perf';
|
|
26
|
+
|
|
27
|
+
// Create store
|
|
28
|
+
const store = createEveryState({ count: 0 });
|
|
29
|
+
|
|
30
|
+
// Attach perf monitor
|
|
31
|
+
const perf = createPerfMonitor(store);
|
|
32
|
+
mountOverlay(perf, document.body);
|
|
33
|
+
|
|
34
|
+
// Subscribe to count changes
|
|
35
|
+
store.subscribe('count', (value) => {
|
|
36
|
+
$('count').textContent = value;
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
// Increment on button click
|
|
40
|
+
$('increment').onclick = () => {
|
|
41
|
+
const current = store.get('count');
|
|
42
|
+
store.set('count', current + 1);
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
// Event Sequence Tests
|
|
46
|
+
$('runTests').onclick = () => {
|
|
47
|
+
const results = [];
|
|
48
|
+
let pass = 0, fail = 0;
|
|
49
|
+
function assert(label, cond) {
|
|
50
|
+
if (cond) { pass++; results.push(' OK ' + label); }
|
|
51
|
+
else { fail++; results.push(' FAIL ' + label); }
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
store.set('count', 0);
|
|
55
|
+
assert('initial count is 0', store.get('count') === 0);
|
|
56
|
+
|
|
57
|
+
store.set('count', 5);
|
|
58
|
+
assert('set count to 5', store.get('count') === 5);
|
|
59
|
+
assert('DOM updated', $('count').textContent === '5');
|
|
60
|
+
|
|
61
|
+
let fired = false;
|
|
62
|
+
const unsub = store.subscribe('count', () => { fired = true; });
|
|
63
|
+
store.set('count', 6);
|
|
64
|
+
assert('subscriber fires on set', fired);
|
|
65
|
+
unsub();
|
|
66
|
+
fired = false;
|
|
67
|
+
store.set('count', 7);
|
|
68
|
+
assert('unsubscribe stops fire', !fired);
|
|
69
|
+
|
|
70
|
+
// Perf recorded events
|
|
71
|
+
const r = perf.report();
|
|
72
|
+
assert('perf tracked sets', r.summary.totalSets > 0);
|
|
73
|
+
|
|
74
|
+
store.set('count', 0);
|
|
75
|
+
$('testLog').textContent = results.join('\n') + `\n\n${pass} passed, ${fail} failed`;
|
|
76
|
+
};
|
|
77
|
+
</script>
|
|
78
|
+
</body>
|
|
79
|
+
</html>
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# 001 Counter - Minimal EveryState Example
|
|
2
|
+
|
|
3
|
+
The simplest possible EveryState example: a counter with one button.
|
|
4
|
+
|
|
5
|
+
## What's Here
|
|
6
|
+
|
|
7
|
+
- `everyState.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 = createEveryState({ 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
|
+
- **`createEveryState(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
|
|
@@ -0,0 +1,83 @@
|
|
|
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 - EveryState</title>
|
|
7
|
+
<script type="importmap">
|
|
8
|
+
{ "imports": {
|
|
9
|
+
"@everystate/core": "../../../everystate-core/index.js",
|
|
10
|
+
"@everystate/perf": "../../../everystate-perf/index.js"
|
|
11
|
+
}}
|
|
12
|
+
</script>
|
|
13
|
+
</head>
|
|
14
|
+
<body>
|
|
15
|
+
<h1>Counter: <span id="count">0</span></h1>
|
|
16
|
+
<button id="increment">+</button>
|
|
17
|
+
<button id="decrement">-</button>
|
|
18
|
+
<button id="double">x2</button>
|
|
19
|
+
<hr>
|
|
20
|
+
<button id="runTests">Run Tests</button>
|
|
21
|
+
<pre id="testLog"></pre>
|
|
22
|
+
|
|
23
|
+
<script type="module">
|
|
24
|
+
import { createEveryState } from '@everystate/core';
|
|
25
|
+
import { createPerfMonitor, mountOverlay } from '@everystate/perf';
|
|
26
|
+
|
|
27
|
+
const store = createEveryState({ count: 0 });
|
|
28
|
+
const perf = createPerfMonitor(store);
|
|
29
|
+
mountOverlay(perf, document.body);
|
|
30
|
+
|
|
31
|
+
store.subscribe('count', (value) => {
|
|
32
|
+
document.getElementById('count').textContent = value;
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
document.getElementById('increment').onclick = () => {
|
|
36
|
+
store.set('count', store.get('count') + 1);
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
document.getElementById('decrement').onclick = () => {
|
|
40
|
+
store.set('count', store.get('count') - 1);
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
document.getElementById('double').onclick = () => {
|
|
44
|
+
store.set('count', store.get('count') * 2);
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
// Event Sequence Tests
|
|
48
|
+
document.getElementById('runTests').onclick = () => {
|
|
49
|
+
const results = [];
|
|
50
|
+
let pass = 0, fail = 0;
|
|
51
|
+
function assert(label, cond) {
|
|
52
|
+
if (cond) { pass++; results.push(' OK ' + label); }
|
|
53
|
+
else { fail++; results.push(' FAIL ' + label); }
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
store.set('count', 0);
|
|
57
|
+
assert('reset to 0', store.get('count') === 0);
|
|
58
|
+
|
|
59
|
+
store.set('count', store.get('count') + 1);
|
|
60
|
+
assert('increment to 1', store.get('count') === 1);
|
|
61
|
+
|
|
62
|
+
store.set('count', store.get('count') - 1);
|
|
63
|
+
assert('decrement back to 0', store.get('count') === 0);
|
|
64
|
+
|
|
65
|
+
store.set('count', 3);
|
|
66
|
+
store.set('count', store.get('count') * 2);
|
|
67
|
+
assert('double 3 = 6', store.get('count') === 6);
|
|
68
|
+
|
|
69
|
+
const seq = [];
|
|
70
|
+
const unsub = store.subscribe('count', (v) => seq.push(v));
|
|
71
|
+
store.set('count', 10);
|
|
72
|
+
store.set('count', 20);
|
|
73
|
+
assert('subscriber sequence', seq[0] === 10 && seq[1] === 20);
|
|
74
|
+
unsub();
|
|
75
|
+
|
|
76
|
+
assert('perf tracked', perf.report().summary.totalSets > 0);
|
|
77
|
+
|
|
78
|
+
store.set('count', 0);
|
|
79
|
+
document.getElementById('testLog').textContent = results.join('\n') + `\n\n${pass} passed, ${fail} failed`;
|
|
80
|
+
};
|
|
81
|
+
</script>
|
|
82
|
+
</body>
|
|
83
|
+
</html>
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# 001 Counter - Minimal EveryState Example
|
|
2
|
+
|
|
3
|
+
The simplest possible EveryState example: a counter with one button.
|
|
4
|
+
|
|
5
|
+
## What's Here
|
|
6
|
+
|
|
7
|
+
- `everyState.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 = createEveryState({ 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
|
+
- **`createEveryState(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
|
|
@@ -0,0 +1,68 @@
|
|
|
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 - EveryState</title>
|
|
7
|
+
<script type="importmap">
|
|
8
|
+
{ "imports": {
|
|
9
|
+
"@everystate/core": "../../../everystate-core/index.js",
|
|
10
|
+
"@everystate/perf": "../../../everystate-perf/index.js"
|
|
11
|
+
}}
|
|
12
|
+
</script>
|
|
13
|
+
</head>
|
|
14
|
+
<body>
|
|
15
|
+
<h1>Type something:</h1>
|
|
16
|
+
<input type="text" id="textInput" placeholder="Start typing...">
|
|
17
|
+
<p id="output"></p>
|
|
18
|
+
<hr>
|
|
19
|
+
<button id="runTests">Run Tests</button>
|
|
20
|
+
<pre id="testLog"></pre>
|
|
21
|
+
|
|
22
|
+
<script type="module">
|
|
23
|
+
import { createEveryState } from '@everystate/core';
|
|
24
|
+
import { createPerfMonitor, mountOverlay } from '@everystate/perf';
|
|
25
|
+
|
|
26
|
+
const store = createEveryState({ text: '' });
|
|
27
|
+
const perf = createPerfMonitor(store);
|
|
28
|
+
mountOverlay(perf, document.body);
|
|
29
|
+
|
|
30
|
+
store.subscribe('text', (value) => {
|
|
31
|
+
document.getElementById('output').textContent = value;
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
document.getElementById('textInput').oninput = (e) => {
|
|
35
|
+
store.set('text', e.target.value);
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
// Event Sequence Tests
|
|
39
|
+
document.getElementById('runTests').onclick = () => {
|
|
40
|
+
const results = [];
|
|
41
|
+
let pass = 0, fail = 0;
|
|
42
|
+
function assert(label, cond) {
|
|
43
|
+
if (cond) { pass++; results.push(' OK ' + label); }
|
|
44
|
+
else { fail++; results.push(' FAIL ' + label); }
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
store.set('text', 'hello');
|
|
48
|
+
assert('set text', store.get('text') === 'hello');
|
|
49
|
+
assert('DOM updated', document.getElementById('output').textContent === 'hello');
|
|
50
|
+
|
|
51
|
+
store.set('text', '');
|
|
52
|
+
assert('clear text', store.get('text') === '');
|
|
53
|
+
|
|
54
|
+
const seq = [];
|
|
55
|
+
const unsub = store.subscribe('text', (v) => seq.push(v));
|
|
56
|
+
store.set('text', 'a');
|
|
57
|
+
store.set('text', 'ab');
|
|
58
|
+
assert('subscriber sequence', seq[0] === 'a' && seq[1] === 'ab');
|
|
59
|
+
unsub();
|
|
60
|
+
|
|
61
|
+
assert('perf tracked', perf.report().summary.totalSets > 0);
|
|
62
|
+
|
|
63
|
+
store.set('text', '');
|
|
64
|
+
document.getElementById('testLog').textContent = results.join('\n') + `\n\n${pass} passed, ${fail} failed`;
|
|
65
|
+
};
|
|
66
|
+
</script>
|
|
67
|
+
</body>
|
|
68
|
+
</html>
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# 004 Computed State - Derived Values
|
|
2
|
+
|
|
3
|
+
Shows how trivial it is to create computed/derived state in EveryState.
|
|
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
|
+
**EveryState:** 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.
|
|
@@ -0,0 +1,83 @@
|
|
|
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 - EveryState</title>
|
|
7
|
+
<script type="importmap">
|
|
8
|
+
{ "imports": {
|
|
9
|
+
"@everystate/core": "../../../everystate-core/index.js",
|
|
10
|
+
"@everystate/perf": "../../../everystate-perf/index.js"
|
|
11
|
+
}}
|
|
12
|
+
</script>
|
|
13
|
+
</head>
|
|
14
|
+
<body>
|
|
15
|
+
<h1>Computed State</h1>
|
|
16
|
+
|
|
17
|
+
<label>First Name: <input type="text" id="firstName" placeholder="Abraham"></label><br>
|
|
18
|
+
<label>Last Name: <input type="text" id="lastName" placeholder="Lincoln"></label><br>
|
|
19
|
+
|
|
20
|
+
<p><strong>Full Name:</strong> <span id="fullName"></span></p>
|
|
21
|
+
<p><strong>Character Count:</strong> <span id="charCount">0</span></p>
|
|
22
|
+
<hr>
|
|
23
|
+
<button id="runTests">Run Tests</button>
|
|
24
|
+
<pre id="testLog"></pre>
|
|
25
|
+
|
|
26
|
+
<script type="module">
|
|
27
|
+
import { createEveryState } from '@everystate/core';
|
|
28
|
+
import { createPerfMonitor, mountOverlay } from '@everystate/perf';
|
|
29
|
+
|
|
30
|
+
const store = createEveryState({ firstName: '', lastName: '' });
|
|
31
|
+
const perf = createPerfMonitor(store);
|
|
32
|
+
mountOverlay(perf, document.body);
|
|
33
|
+
|
|
34
|
+
const updateFullName = () => {
|
|
35
|
+
const first = store.get('firstName');
|
|
36
|
+
const last = store.get('lastName');
|
|
37
|
+
document.getElementById('fullName').textContent = `${first} ${last}`.trim() || '(empty)';
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
const updateCharCount = () => {
|
|
41
|
+
const first = store.get('firstName');
|
|
42
|
+
const last = store.get('lastName');
|
|
43
|
+
document.getElementById('charCount').textContent = (first + last).length;
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
store.subscribe('*', () => { updateFullName(); updateCharCount(); });
|
|
47
|
+
|
|
48
|
+
document.getElementById('firstName').oninput = (e) => { store.set('firstName', e.target.value); };
|
|
49
|
+
document.getElementById('lastName').oninput = (e) => { store.set('lastName', e.target.value); };
|
|
50
|
+
|
|
51
|
+
updateFullName();
|
|
52
|
+
updateCharCount();
|
|
53
|
+
|
|
54
|
+
// Event Sequence Tests
|
|
55
|
+
document.getElementById('runTests').onclick = () => {
|
|
56
|
+
const results = [];
|
|
57
|
+
let pass = 0, fail = 0;
|
|
58
|
+
function assert(label, cond) {
|
|
59
|
+
if (cond) { pass++; results.push(' OK ' + label); }
|
|
60
|
+
else { fail++; results.push(' FAIL ' + label); }
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
store.set('firstName', 'Alice');
|
|
64
|
+
store.set('lastName', 'Smith');
|
|
65
|
+
assert('fullName computed', document.getElementById('fullName').textContent === 'Alice Smith');
|
|
66
|
+
assert('charCount computed', document.getElementById('charCount').textContent === '10');
|
|
67
|
+
|
|
68
|
+
// Global wildcard fires on any path
|
|
69
|
+
let globalFired = 0;
|
|
70
|
+
const unsub = store.subscribe('*', () => globalFired++);
|
|
71
|
+
store.set('firstName', 'Bob');
|
|
72
|
+
assert('global wildcard fires', globalFired >= 1);
|
|
73
|
+
unsub();
|
|
74
|
+
|
|
75
|
+
assert('perf tracked', perf.report().summary.totalSets > 0);
|
|
76
|
+
|
|
77
|
+
store.set('firstName', '');
|
|
78
|
+
store.set('lastName', '');
|
|
79
|
+
document.getElementById('testLog').textContent = results.join('\n') + `\n\n${pass} passed, ${fail} failed`;
|
|
80
|
+
};
|
|
81
|
+
</script>
|
|
82
|
+
</body>
|
|
83
|
+
</html>
|
|
@@ -0,0 +1,42 @@
|
|
|
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 = createEveryState({ 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
|
+
**EveryState:** 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.
|
|
@@ -0,0 +1,68 @@
|
|
|
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 - EveryState</title>
|
|
7
|
+
<script type="importmap">
|
|
8
|
+
{ "imports": {
|
|
9
|
+
"@everystate/core": "../../../everystate-core/index.js",
|
|
10
|
+
"@everystate/perf": "../../../everystate-perf/index.js"
|
|
11
|
+
}}
|
|
12
|
+
</script>
|
|
13
|
+
</head>
|
|
14
|
+
<body>
|
|
15
|
+
<h1>Conditional Rendering</h1>
|
|
16
|
+
|
|
17
|
+
<label>
|
|
18
|
+
<input type="checkbox" id="toggle">
|
|
19
|
+
Show secret message
|
|
20
|
+
</label>
|
|
21
|
+
|
|
22
|
+
<p id="message" style="display: none;">You found the secret message!</p>
|
|
23
|
+
<hr>
|
|
24
|
+
<button id="runTests">Run Tests</button>
|
|
25
|
+
<pre id="testLog"></pre>
|
|
26
|
+
|
|
27
|
+
<script type="module">
|
|
28
|
+
import { createEveryState } from '@everystate/core';
|
|
29
|
+
import { createPerfMonitor, mountOverlay } from '@everystate/perf';
|
|
30
|
+
|
|
31
|
+
const store = createEveryState({ isVisible: false });
|
|
32
|
+
const perf = createPerfMonitor(store);
|
|
33
|
+
mountOverlay(perf, document.body);
|
|
34
|
+
|
|
35
|
+
store.subscribe('isVisible', (value) => {
|
|
36
|
+
document.getElementById('message').style.display = value ? 'block' : 'none';
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
document.getElementById('toggle').onchange = (e) => {
|
|
40
|
+
store.set('isVisible', e.target.checked);
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
// Event Sequence Tests
|
|
44
|
+
document.getElementById('runTests').onclick = () => {
|
|
45
|
+
const results = [];
|
|
46
|
+
let pass = 0, fail = 0;
|
|
47
|
+
function assert(label, cond) {
|
|
48
|
+
if (cond) { pass++; results.push(' OK ' + label); }
|
|
49
|
+
else { fail++; results.push(' FAIL ' + label); }
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
assert('initially hidden', store.get('isVisible') === false);
|
|
53
|
+
assert('DOM hidden', document.getElementById('message').style.display === 'none');
|
|
54
|
+
|
|
55
|
+
store.set('isVisible', true);
|
|
56
|
+
assert('set visible', store.get('isVisible') === true);
|
|
57
|
+
assert('DOM shown', document.getElementById('message').style.display === 'block');
|
|
58
|
+
|
|
59
|
+
store.set('isVisible', false);
|
|
60
|
+
assert('set hidden again', document.getElementById('message').style.display === 'none');
|
|
61
|
+
|
|
62
|
+
assert('perf tracked', perf.report().summary.totalSets > 0);
|
|
63
|
+
|
|
64
|
+
document.getElementById('testLog').textContent = results.join('\n') + `\n\n${pass} passed, ${fail} failed`;
|
|
65
|
+
};
|
|
66
|
+
</script>
|
|
67
|
+
</body>
|
|
68
|
+
</html>
|
|
@@ -0,0 +1,49 @@
|
|
|
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 = createEveryState({ 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
|
+
**EveryState:** 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).
|