@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
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# 007 Form Validation - Real-time Feedback
|
|
2
|
+
|
|
3
|
+
Demonstrates form validation with multiple state paths and computed validity.
|
|
4
|
+
|
|
5
|
+
## What's Here
|
|
6
|
+
|
|
7
|
+
- Email and password inputs
|
|
8
|
+
- Real-time validation messages
|
|
9
|
+
- Submit button enabled only when form is valid
|
|
10
|
+
- **No form library needed** - just state and functions
|
|
11
|
+
|
|
12
|
+
## How It Works
|
|
13
|
+
|
|
14
|
+
```javascript
|
|
15
|
+
// 1. Store input values AND validation state
|
|
16
|
+
const store = createEveryState({
|
|
17
|
+
email: '',
|
|
18
|
+
password: '',
|
|
19
|
+
emailValid: false,
|
|
20
|
+
passwordValid: false
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
// 2. Validate on input change
|
|
24
|
+
store.subscribe('email', (value) => {
|
|
25
|
+
const isValid = validateEmail(value);
|
|
26
|
+
store.set('emailValid', isValid);
|
|
27
|
+
// Show error message
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
// 3. Enable submit when all fields valid
|
|
31
|
+
store.subscribe('emailValid', updateSubmitButton);
|
|
32
|
+
store.subscribe('passwordValid', updateSubmitButton);
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Key Insight
|
|
36
|
+
|
|
37
|
+
**Validation is just derived state.**
|
|
38
|
+
|
|
39
|
+
- Input values are **source state**
|
|
40
|
+
- Validation flags are **derived state**
|
|
41
|
+
- Submit button state is **computed from derived state**
|
|
42
|
+
|
|
43
|
+
Other frameworks need:
|
|
44
|
+
- React: `useForm` hooks, validation libraries
|
|
45
|
+
- Vue: `v-model` + validation plugins
|
|
46
|
+
- Svelte: Stores + validation actions
|
|
47
|
+
|
|
48
|
+
**EveryState:** Just subscribe to inputs, validate, and update state. That's it.
|
|
49
|
+
|
|
50
|
+
## Run It
|
|
51
|
+
|
|
52
|
+
Open `index.html` in a browser. Type invalid data to see error messages. Submit button enables when both fields are valid.
|
|
@@ -0,0 +1,108 @@
|
|
|
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>007 Form Validation - 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>Sign Up Form</h1>
|
|
16
|
+
|
|
17
|
+
<label>Email: <input type="email" id="email" placeholder="you@example.com"></label>
|
|
18
|
+
<p id="emailError" style="color: red;"></p>
|
|
19
|
+
|
|
20
|
+
<label>Password: <input type="password" id="password" placeholder="Min 8 characters"></label>
|
|
21
|
+
<p id="passwordError" style="color: red;"></p>
|
|
22
|
+
|
|
23
|
+
<button id="submitBtn" disabled>Submit</button>
|
|
24
|
+
<p id="submitMessage" style="color: green;"></p>
|
|
25
|
+
<hr>
|
|
26
|
+
<button id="runTests">Run Tests</button>
|
|
27
|
+
<pre id="testLog"></pre>
|
|
28
|
+
|
|
29
|
+
<script type="module">
|
|
30
|
+
import { createEveryState } from '@everystate/core';
|
|
31
|
+
import { createPerfMonitor, mountOverlay } from '@everystate/perf';
|
|
32
|
+
|
|
33
|
+
const store = createEveryState({ email: '', password: '', emailValid: false, passwordValid: false });
|
|
34
|
+
const perf = createPerfMonitor(store);
|
|
35
|
+
mountOverlay(perf, document.body);
|
|
36
|
+
|
|
37
|
+
const validateEmail = (email) => email.includes('@') && email.includes('.');
|
|
38
|
+
const validatePassword = (password) => password.length >= 8;
|
|
39
|
+
|
|
40
|
+
const updateSubmitButton = () => {
|
|
41
|
+
document.getElementById('submitBtn').disabled = !(store.get('emailValid') && store.get('passwordValid'));
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
store.subscribe('email', (value) => {
|
|
45
|
+
const isValid = validateEmail(value);
|
|
46
|
+
store.set('emailValid', isValid);
|
|
47
|
+
document.getElementById('emailError').textContent = value && !isValid ? 'Invalid email address' : '';
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
store.subscribe('password', (value) => {
|
|
51
|
+
const isValid = validatePassword(value);
|
|
52
|
+
store.set('passwordValid', isValid);
|
|
53
|
+
document.getElementById('passwordError').textContent = value && !isValid ? 'Password must be at least 8 characters' : '';
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
store.subscribe('emailValid', updateSubmitButton);
|
|
57
|
+
store.subscribe('passwordValid', updateSubmitButton);
|
|
58
|
+
|
|
59
|
+
document.getElementById('email').oninput = (e) => { store.set('email', e.target.value); };
|
|
60
|
+
document.getElementById('password').oninput = (e) => { store.set('password', e.target.value); };
|
|
61
|
+
|
|
62
|
+
document.getElementById('submitBtn').onclick = () => {
|
|
63
|
+
document.getElementById('submitMessage').textContent = `Form submitted for ${store.get('email')}`;
|
|
64
|
+
document.getElementById('email').value = '';
|
|
65
|
+
document.getElementById('password').value = '';
|
|
66
|
+
store.set('email', '');
|
|
67
|
+
store.set('password', '');
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
// Event Sequence Tests
|
|
71
|
+
document.getElementById('runTests').onclick = () => {
|
|
72
|
+
const results = [];
|
|
73
|
+
let pass = 0, fail = 0;
|
|
74
|
+
function assert(label, cond) {
|
|
75
|
+
if (cond) { pass++; results.push(' OK ' + label); }
|
|
76
|
+
else { fail++; results.push(' FAIL ' + label); }
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
store.set('email', 'bad');
|
|
80
|
+
assert('invalid email sets emailValid=false', store.get('emailValid') === false);
|
|
81
|
+
|
|
82
|
+
store.set('email', 'a@b.c');
|
|
83
|
+
assert('valid email sets emailValid=true', store.get('emailValid') === true);
|
|
84
|
+
|
|
85
|
+
store.set('password', 'short');
|
|
86
|
+
assert('short password invalid', store.get('passwordValid') === false);
|
|
87
|
+
assert('submit disabled when invalid', document.getElementById('submitBtn').disabled === true);
|
|
88
|
+
|
|
89
|
+
store.set('password', 'longpassword');
|
|
90
|
+
assert('long password valid', store.get('passwordValid') === true);
|
|
91
|
+
assert('submit enabled when both valid', document.getElementById('submitBtn').disabled === false);
|
|
92
|
+
|
|
93
|
+
// Cascading: email fires emailValid fires updateSubmitButton
|
|
94
|
+
const seq = [];
|
|
95
|
+
const u1 = store.subscribe('emailValid', () => seq.push('emailValid'));
|
|
96
|
+
store.set('email', 'x@y.z');
|
|
97
|
+
assert('cascading: email -> emailValid', seq.includes('emailValid'));
|
|
98
|
+
u1();
|
|
99
|
+
|
|
100
|
+
assert('perf tracked', perf.report().summary.totalSets > 0);
|
|
101
|
+
|
|
102
|
+
store.set('email', '');
|
|
103
|
+
store.set('password', '');
|
|
104
|
+
document.getElementById('testLog').textContent = results.join('\n') + `\n\n${pass} passed, ${fail} failed`;
|
|
105
|
+
};
|
|
106
|
+
</script>
|
|
107
|
+
</body>
|
|
108
|
+
</html>
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# 010 Decoupled Components - Shared State
|
|
2
|
+
|
|
3
|
+
Demonstrates how components can communicate through shared state without direct coupling.
|
|
4
|
+
|
|
5
|
+
## What's Here
|
|
6
|
+
|
|
7
|
+
- **Component A (Writer):** Sends messages
|
|
8
|
+
- **Component B (Reader):** Displays current message
|
|
9
|
+
- **Component C (Logger):** Logs all messages with timestamps
|
|
10
|
+
- **Zero coupling:** Components don't know about each other
|
|
11
|
+
|
|
12
|
+
## How It Works
|
|
13
|
+
|
|
14
|
+
```javascript
|
|
15
|
+
// Shared store - the ONLY connection
|
|
16
|
+
const store = createEveryState({ message: '' });
|
|
17
|
+
|
|
18
|
+
// Component A: Writes to state
|
|
19
|
+
document.getElementById('sendBtn').onclick = () => {
|
|
20
|
+
store.set('message', inputValue);
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
// Component B: Reads from state
|
|
24
|
+
store.subscribe('message', (value) => {
|
|
25
|
+
document.getElementById('display').textContent = value;
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
// Component C: Also reads from state
|
|
29
|
+
store.subscribe('message', (value) => {
|
|
30
|
+
logMessage(value);
|
|
31
|
+
});
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Key Insight
|
|
35
|
+
|
|
36
|
+
**State is the interface between components.**
|
|
37
|
+
|
|
38
|
+
Components communicate by:
|
|
39
|
+
1. Writing to shared state
|
|
40
|
+
2. Subscribing to shared state
|
|
41
|
+
3. **Never** calling each other directly
|
|
42
|
+
|
|
43
|
+
This is the **pub/sub pattern** in action:
|
|
44
|
+
- ✅ Components are decoupled
|
|
45
|
+
- ✅ Easy to add/remove components
|
|
46
|
+
- ✅ No prop drilling
|
|
47
|
+
- ✅ No callbacks passed down
|
|
48
|
+
|
|
49
|
+
Other frameworks need:
|
|
50
|
+
- React: Context API, prop drilling, or state management libraries
|
|
51
|
+
- Vue: Provide/inject or Vuex
|
|
52
|
+
- Svelte: Context API or stores
|
|
53
|
+
|
|
54
|
+
**EveryState:** Just share the store. That's it.
|
|
55
|
+
|
|
56
|
+
## Architecture Pattern
|
|
57
|
+
|
|
58
|
+
This demonstrates the **mediator pattern**:
|
|
59
|
+
- Components don't talk to each other
|
|
60
|
+
- They talk to the store
|
|
61
|
+
- The store mediates all communication
|
|
62
|
+
|
|
63
|
+
This is how the full EveryState framework works:
|
|
64
|
+
- Intents → State changes
|
|
65
|
+
- State changes → UI updates
|
|
66
|
+
- Everything is decoupled through events
|
|
67
|
+
|
|
68
|
+
## Run It
|
|
69
|
+
|
|
70
|
+
Open `index.html`, type messages, and watch all three components react independently.
|
|
71
|
+
|
|
72
|
+
## Try This
|
|
73
|
+
|
|
74
|
+
Add a fourth component that counts vowels in messages. It only needs to subscribe to `'message'` - no other code changes needed.
|
|
@@ -0,0 +1,117 @@
|
|
|
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>010 Decoupled Components - EveryState</title>
|
|
7
|
+
<style>
|
|
8
|
+
.component { border: 2px solid #333; padding: 20px; margin: 10px 0; }
|
|
9
|
+
</style>
|
|
10
|
+
<script type="importmap">
|
|
11
|
+
{ "imports": {
|
|
12
|
+
"@everystate/core": "../../../everystate-core/index.js",
|
|
13
|
+
"@everystate/perf": "../../../everystate-perf/index.js"
|
|
14
|
+
}}
|
|
15
|
+
</script>
|
|
16
|
+
</head>
|
|
17
|
+
<body>
|
|
18
|
+
<h1>Decoupled Components</h1>
|
|
19
|
+
<p>Three independent "components" sharing state without knowing about each other.</p>
|
|
20
|
+
|
|
21
|
+
<div class="component">
|
|
22
|
+
<h2>Component A: Writer</h2>
|
|
23
|
+
<input type="text" id="messageInput" placeholder="Type a message...">
|
|
24
|
+
<button id="sendBtn">Send</button>
|
|
25
|
+
</div>
|
|
26
|
+
|
|
27
|
+
<div class="component">
|
|
28
|
+
<h2>Component B: Reader</h2>
|
|
29
|
+
<p><strong>Received:</strong> <span id="messageDisplay">(nothing yet)</span></p>
|
|
30
|
+
<p><small>Message count: <span id="messageCount">0</span></small></p>
|
|
31
|
+
</div>
|
|
32
|
+
|
|
33
|
+
<div class="component">
|
|
34
|
+
<h2>Component C: Logger</h2>
|
|
35
|
+
<ul id="messageLog"></ul>
|
|
36
|
+
</div>
|
|
37
|
+
|
|
38
|
+
<hr>
|
|
39
|
+
<button id="runTests">Run Tests</button>
|
|
40
|
+
<pre id="testLog"></pre>
|
|
41
|
+
|
|
42
|
+
<script type="module">
|
|
43
|
+
import { createEveryState } from '@everystate/core';
|
|
44
|
+
import { createPerfMonitor, mountOverlay } from '@everystate/perf';
|
|
45
|
+
|
|
46
|
+
const store = createEveryState({ message: '', messageCount: 0 });
|
|
47
|
+
const perf = createPerfMonitor(store);
|
|
48
|
+
mountOverlay(perf, document.body);
|
|
49
|
+
|
|
50
|
+
// Component A: Writer
|
|
51
|
+
document.getElementById('sendBtn').onclick = () => {
|
|
52
|
+
const input = document.getElementById('messageInput');
|
|
53
|
+
const value = input.value.trim();
|
|
54
|
+
if (value) {
|
|
55
|
+
store.set('message', value);
|
|
56
|
+
store.set('messageCount', store.get('messageCount') + 1);
|
|
57
|
+
input.value = '';
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
document.getElementById('messageInput').onkeypress = (e) => {
|
|
62
|
+
if (e.key === 'Enter') document.getElementById('sendBtn').click();
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
// Component B: Reader
|
|
66
|
+
store.subscribe('message', (value) => {
|
|
67
|
+
document.getElementById('messageDisplay').textContent = value || '(nothing yet)';
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
store.subscribe('messageCount', (value) => {
|
|
71
|
+
document.getElementById('messageCount').textContent = value;
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
// Component C: Logger
|
|
75
|
+
store.subscribe('message', (value) => {
|
|
76
|
+
if (value) {
|
|
77
|
+
const li = document.createElement('li');
|
|
78
|
+
li.textContent = `[${new Date().toLocaleTimeString()}] ${value}`;
|
|
79
|
+
document.getElementById('messageLog').appendChild(li);
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
// Event Sequence Tests
|
|
84
|
+
document.getElementById('runTests').onclick = () => {
|
|
85
|
+
const results = [];
|
|
86
|
+
let pass = 0, fail = 0;
|
|
87
|
+
function assert(label, cond) {
|
|
88
|
+
if (cond) { pass++; results.push(' OK ' + label); }
|
|
89
|
+
else { fail++; results.push(' FAIL ' + label); }
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
store.set('message', 'test-msg');
|
|
93
|
+
assert('reader shows message', document.getElementById('messageDisplay').textContent === 'test-msg');
|
|
94
|
+
|
|
95
|
+
store.set('messageCount', 0);
|
|
96
|
+
store.set('messageCount', store.get('messageCount') + 1);
|
|
97
|
+
assert('count incremented', store.get('messageCount') === 1);
|
|
98
|
+
assert('count DOM updated', document.getElementById('messageCount').textContent === '1');
|
|
99
|
+
|
|
100
|
+
// Multiple subscribers on same path
|
|
101
|
+
let fires = 0;
|
|
102
|
+
const u1 = store.subscribe('message', () => fires++);
|
|
103
|
+
const u2 = store.subscribe('message', () => fires++);
|
|
104
|
+
store.set('message', 'multi');
|
|
105
|
+
assert('multiple subs both fire', fires === 2);
|
|
106
|
+
u1(); u2();
|
|
107
|
+
|
|
108
|
+
assert('logger has entries', document.getElementById('messageLog').querySelectorAll('li').length > 0);
|
|
109
|
+
assert('perf tracked', perf.report().summary.totalSets > 0);
|
|
110
|
+
|
|
111
|
+
store.set('message', '');
|
|
112
|
+
store.set('messageCount', 0);
|
|
113
|
+
document.getElementById('testLog').textContent = results.join('\n') + `\n\n${pass} passed, ${fail} failed`;
|
|
114
|
+
};
|
|
115
|
+
</script>
|
|
116
|
+
</body>
|
|
117
|
+
</html>
|
|
@@ -0,0 +1,36 @@
|
|
|
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>@everystate/view Examples</title>
|
|
7
|
+
<style>
|
|
8
|
+
body { font-family: system-ui, sans-serif; max-width: 600px; margin: 2rem auto; padding: 0 1rem; }
|
|
9
|
+
a { display: block; padding: 0.5rem 0; color: #3b82f6; }
|
|
10
|
+
.note { background: #f0f9ff; border: 1px solid #bae6fd; border-radius: 0.5rem; padding: 1rem; margin-top: 1rem; }
|
|
11
|
+
</style>
|
|
12
|
+
</head>
|
|
13
|
+
<body>
|
|
14
|
+
<h1>@everystate/view Examples</h1>
|
|
15
|
+
<p>Interactive examples demonstrating <code>@everystate/view</code> - view-as-state:</p>
|
|
16
|
+
<ul>
|
|
17
|
+
<li><a href="001/counter/">001 - Counter</a></li>
|
|
18
|
+
<li><a href="002/datatable/">002 - DataTable</a></li>
|
|
19
|
+
<li><a href="003/todo/">003 - Todo (View-as-State)</a></li>
|
|
20
|
+
<li><a href="004/quotesFetcher/">004 - Quotes Fetcher</a></li>
|
|
21
|
+
<li><a href="004_01/quotesFetcher/">004_01 - Quotes Fetcher (Split Modules)</a></li>
|
|
22
|
+
<li><a href="004_02/quotesFetcher/">004_02 - Quotes Fetcher (Dot-Path Registry)</a></li>
|
|
23
|
+
<li><a href="004_03/quotesFetcher/">004_03 - Quotes Fetcher (Uniform Resource Architecture)</a></li>
|
|
24
|
+
<li><a href="004_04/quotesFetcher/">004_04 - Quote Explorer (URA + Archive, Deep Composition)</a></li>
|
|
25
|
+
<li><a href="004_05/quoteExplorer/">004_05 - Conditional Rendering & Parameterization (no showIf, no props)</a></li>
|
|
26
|
+
<li><a href="004_08_V2/">004_08_V2 - Quote Explorer Pro (transparent auto-intent)</a></li>
|
|
27
|
+
<li><a href="006/api-datatable/">006 - API DataTable + Perf</a></li>
|
|
28
|
+
<li><a href="007/apiUsers/">007 - API Users DataTable</a></li>
|
|
29
|
+
</ul>
|
|
30
|
+
<div class="note">
|
|
31
|
+
<strong>Note:</strong> These examples use <code>@everystate/view</code> which requires
|
|
32
|
+
<code>resolve.js</code> and <code>project.js</code> from the <code>everystate-view</code> package.
|
|
33
|
+
They must be served from the <code>everystateAll/</code> root directory.
|
|
34
|
+
</div>
|
|
35
|
+
</body>
|
|
36
|
+
</html>
|
package/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@everystate/examples",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"description": "EveryState Examples: Example applications and patterns",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"keywords": [
|
|
@@ -20,7 +20,5 @@
|
|
|
20
20
|
"type": "git",
|
|
21
21
|
"url": "https://github.com/ImsirovicAjdin/everystate-examples"
|
|
22
22
|
},
|
|
23
|
-
"dependencies": {
|
|
24
|
-
"@uistate/examples": "^1.0.2"
|
|
25
|
-
}
|
|
23
|
+
"dependencies": {}
|
|
26
24
|
}
|