@uistate/core 5.2.0 → 5.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (142) hide show
  1. package/index.js +2 -9
  2. package/package.json +4 -10
  3. package/queryClient.js +55 -0
  4. package/cssState.js +0 -212
  5. package/examples/001-counter/README.md +0 -44
  6. package/examples/001-counter/index.html +0 -33
  7. package/examples/002-counter-improved/README.md +0 -44
  8. package/examples/002-counter-improved/index.html +0 -47
  9. package/examples/003-input-reactive/README.md +0 -44
  10. package/examples/003-input-reactive/index.html +0 -33
  11. package/examples/004-computed-state/README.md +0 -45
  12. package/examples/004-computed-state/index.html +0 -65
  13. package/examples/005-conditional-rendering/README.md +0 -42
  14. package/examples/005-conditional-rendering/index.html +0 -39
  15. package/examples/006-list-rendering/README.md +0 -49
  16. package/examples/006-list-rendering/index.html +0 -63
  17. package/examples/007-form-validation/README.md +0 -52
  18. package/examples/007-form-validation/index.html +0 -102
  19. package/examples/008-undo-redo/README.md +0 -70
  20. package/examples/008-undo-redo/index.html +0 -108
  21. package/examples/009-localStorage-side-effects/README.md +0 -72
  22. package/examples/009-localStorage-side-effects/index.html +0 -57
  23. package/examples/010-decoupled-components/README.md +0 -74
  24. package/examples/010-decoupled-components/index.html +0 -93
  25. package/examples/011-async-patterns/README.md +0 -98
  26. package/examples/011-async-patterns/index.html +0 -132
  27. package/examples/028-counter-improved-eventTest/LICENSE +0 -55
  28. package/examples/028-counter-improved-eventTest/README.md +0 -131
  29. package/examples/028-counter-improved-eventTest/app/store.js +0 -9
  30. package/examples/028-counter-improved-eventTest/index.html +0 -49
  31. package/examples/028-counter-improved-eventTest/runtime/core/behaviors.runtime.js +0 -282
  32. package/examples/028-counter-improved-eventTest/runtime/core/eventState.js +0 -100
  33. package/examples/028-counter-improved-eventTest/runtime/core/eventStateNew.js +0 -149
  34. package/examples/028-counter-improved-eventTest/runtime/core/helpers.js +0 -212
  35. package/examples/028-counter-improved-eventTest/runtime/core/router.js +0 -271
  36. package/examples/028-counter-improved-eventTest/store.d.ts +0 -8
  37. package/examples/028-counter-improved-eventTest/style.css +0 -170
  38. package/examples/028-counter-improved-eventTest/tests/README.md +0 -208
  39. package/examples/028-counter-improved-eventTest/tests/counter.test.js +0 -116
  40. package/examples/028-counter-improved-eventTest/tests/eventTest.js +0 -176
  41. package/examples/028-counter-improved-eventTest/tests/generateTypes.js +0 -168
  42. package/examples/028-counter-improved-eventTest/tests/run.js +0 -20
  43. package/examples/030-todo-app-with-eventTest/LICENSE +0 -55
  44. package/examples/030-todo-app-with-eventTest/README.md +0 -121
  45. package/examples/030-todo-app-with-eventTest/app/router.js +0 -25
  46. package/examples/030-todo-app-with-eventTest/app/store.js +0 -16
  47. package/examples/030-todo-app-with-eventTest/app/views/home.js +0 -11
  48. package/examples/030-todo-app-with-eventTest/app/views/todoDemo.js +0 -88
  49. package/examples/030-todo-app-with-eventTest/index.html +0 -65
  50. package/examples/030-todo-app-with-eventTest/runtime/core/behaviors.runtime.js +0 -282
  51. package/examples/030-todo-app-with-eventTest/runtime/core/eventState.js +0 -100
  52. package/examples/030-todo-app-with-eventTest/runtime/core/eventStateNew.js +0 -149
  53. package/examples/030-todo-app-with-eventTest/runtime/core/helpers.js +0 -212
  54. package/examples/030-todo-app-with-eventTest/runtime/core/router.js +0 -271
  55. package/examples/030-todo-app-with-eventTest/store.d.ts +0 -18
  56. package/examples/030-todo-app-with-eventTest/style.css +0 -170
  57. package/examples/030-todo-app-with-eventTest/tests/README.md +0 -208
  58. package/examples/030-todo-app-with-eventTest/tests/eventTest.js +0 -176
  59. package/examples/030-todo-app-with-eventTest/tests/generateTypes.js +0 -189
  60. package/examples/030-todo-app-with-eventTest/tests/run.js +0 -20
  61. package/examples/030-todo-app-with-eventTest/tests/todos.test.js +0 -167
  62. package/examples/031-todo-app-with-eventTest/LICENSE +0 -55
  63. package/examples/031-todo-app-with-eventTest/README.md +0 -54
  64. package/examples/031-todo-app-with-eventTest/TUTORIAL.md +0 -390
  65. package/examples/031-todo-app-with-eventTest/WHY_EVENTSTATE.md +0 -777
  66. package/examples/031-todo-app-with-eventTest/app/bridges.js +0 -113
  67. package/examples/031-todo-app-with-eventTest/app/router.js +0 -26
  68. package/examples/031-todo-app-with-eventTest/app/store.js +0 -15
  69. package/examples/031-todo-app-with-eventTest/app/views/home.js +0 -46
  70. package/examples/031-todo-app-with-eventTest/app/views/todoDemo.js +0 -69
  71. package/examples/031-todo-app-with-eventTest/devtools/dock.js +0 -41
  72. package/examples/031-todo-app-with-eventTest/devtools/stateTracker.dock.js +0 -10
  73. package/examples/031-todo-app-with-eventTest/devtools/stateTracker.js +0 -246
  74. package/examples/031-todo-app-with-eventTest/devtools/telemetry.js +0 -104
  75. package/examples/031-todo-app-with-eventTest/devtools/typeGenerator.js +0 -339
  76. package/examples/031-todo-app-with-eventTest/index.html +0 -103
  77. package/examples/031-todo-app-with-eventTest/package-lock.json +0 -2184
  78. package/examples/031-todo-app-with-eventTest/package.json +0 -24
  79. package/examples/031-todo-app-with-eventTest/runtime/core/behaviors.runtime.js +0 -282
  80. package/examples/031-todo-app-with-eventTest/runtime/core/eventState.js +0 -100
  81. package/examples/031-todo-app-with-eventTest/runtime/core/eventStateNew.js +0 -149
  82. package/examples/031-todo-app-with-eventTest/runtime/core/helpers.js +0 -212
  83. package/examples/031-todo-app-with-eventTest/runtime/core/router.js +0 -271
  84. package/examples/031-todo-app-with-eventTest/runtime/extensions/boundary.js +0 -36
  85. package/examples/031-todo-app-with-eventTest/runtime/extensions/converge.js +0 -63
  86. package/examples/031-todo-app-with-eventTest/runtime/extensions/eventState.plus.js +0 -210
  87. package/examples/031-todo-app-with-eventTest/runtime/extensions/hydrate.js +0 -157
  88. package/examples/031-todo-app-with-eventTest/runtime/extensions/queryBinding.js +0 -69
  89. package/examples/031-todo-app-with-eventTest/runtime/forms/computed.js +0 -78
  90. package/examples/031-todo-app-with-eventTest/runtime/forms/meta.js +0 -51
  91. package/examples/031-todo-app-with-eventTest/runtime/forms/submitWithBoundary.js +0 -28
  92. package/examples/031-todo-app-with-eventTest/runtime/forms/validators.js +0 -55
  93. package/examples/031-todo-app-with-eventTest/store.d.ts +0 -23
  94. package/examples/031-todo-app-with-eventTest/style.css +0 -170
  95. package/examples/031-todo-app-with-eventTest/tests/README.md +0 -208
  96. package/examples/031-todo-app-with-eventTest/tests/eventTest.js +0 -176
  97. package/examples/031-todo-app-with-eventTest/tests/generateTypes.js +0 -191
  98. package/examples/031-todo-app-with-eventTest/tests/run.js +0 -20
  99. package/examples/031-todo-app-with-eventTest/tests/todos.test.js +0 -192
  100. package/examples/032-todo-app-with-eventTest/LICENSE +0 -55
  101. package/examples/032-todo-app-with-eventTest/README.md +0 -54
  102. package/examples/032-todo-app-with-eventTest/TUTORIAL.md +0 -390
  103. package/examples/032-todo-app-with-eventTest/WHY_EVENTSTATE.md +0 -777
  104. package/examples/032-todo-app-with-eventTest/app/actions/index.js +0 -153
  105. package/examples/032-todo-app-with-eventTest/app/bridges.js +0 -113
  106. package/examples/032-todo-app-with-eventTest/app/router.js +0 -26
  107. package/examples/032-todo-app-with-eventTest/app/store.js +0 -15
  108. package/examples/032-todo-app-with-eventTest/app/views/home.js +0 -46
  109. package/examples/032-todo-app-with-eventTest/app/views/todoDemo.js +0 -69
  110. package/examples/032-todo-app-with-eventTest/devtools/dock.js +0 -41
  111. package/examples/032-todo-app-with-eventTest/devtools/stateTracker.dock.js +0 -10
  112. package/examples/032-todo-app-with-eventTest/devtools/stateTracker.js +0 -246
  113. package/examples/032-todo-app-with-eventTest/devtools/telemetry.js +0 -104
  114. package/examples/032-todo-app-with-eventTest/devtools/typeGenerator.js +0 -339
  115. package/examples/032-todo-app-with-eventTest/index.html +0 -87
  116. package/examples/032-todo-app-with-eventTest/package-lock.json +0 -2184
  117. package/examples/032-todo-app-with-eventTest/package.json +0 -24
  118. package/examples/032-todo-app-with-eventTest/runtime/core/behaviors.runtime.js +0 -282
  119. package/examples/032-todo-app-with-eventTest/runtime/core/eventState.js +0 -100
  120. package/examples/032-todo-app-with-eventTest/runtime/core/eventStateNew.js +0 -149
  121. package/examples/032-todo-app-with-eventTest/runtime/core/helpers.js +0 -212
  122. package/examples/032-todo-app-with-eventTest/runtime/core/router.js +0 -271
  123. package/examples/032-todo-app-with-eventTest/runtime/extensions/boundary.js +0 -36
  124. package/examples/032-todo-app-with-eventTest/runtime/extensions/converge.js +0 -63
  125. package/examples/032-todo-app-with-eventTest/runtime/extensions/eventState.plus.js +0 -210
  126. package/examples/032-todo-app-with-eventTest/runtime/extensions/hydrate.js +0 -157
  127. package/examples/032-todo-app-with-eventTest/runtime/extensions/queryBinding.js +0 -69
  128. package/examples/032-todo-app-with-eventTest/runtime/forms/computed.js +0 -78
  129. package/examples/032-todo-app-with-eventTest/runtime/forms/meta.js +0 -51
  130. package/examples/032-todo-app-with-eventTest/runtime/forms/submitWithBoundary.js +0 -28
  131. package/examples/032-todo-app-with-eventTest/runtime/forms/validators.js +0 -55
  132. package/examples/032-todo-app-with-eventTest/store.d.ts +0 -23
  133. package/examples/032-todo-app-with-eventTest/style.css +0 -170
  134. package/examples/032-todo-app-with-eventTest/tests/README.md +0 -208
  135. package/examples/032-todo-app-with-eventTest/tests/eventTest.js +0 -176
  136. package/examples/032-todo-app-with-eventTest/tests/generateTypes.js +0 -191
  137. package/examples/032-todo-app-with-eventTest/tests/run.js +0 -20
  138. package/examples/032-todo-app-with-eventTest/tests/todos.test.js +0 -192
  139. package/playground/exercise001.html +0 -38
  140. package/playground/exercise002.html +0 -49
  141. package/stateSerializer.js +0 -267
  142. package/templateManager.js +0 -216
package/index.js CHANGED
@@ -1,17 +1,10 @@
1
1
  /**
2
2
  * UIstate v5 - Core barrel exports
3
3
  *
4
- * EventState is now the primary export for application state management.
5
- * cssState remains available for CSS variable/theme management use cases.
4
+ * EventState is the primary export for application state management.
5
+ * CSS state management has moved to @uistate/css.
6
6
  */
7
7
 
8
8
  // Primary: EventState (recommended for application state)
9
9
  export { createEventState } from './eventStateNew.js';
10
10
  export { createEventState as default } from './eventStateNew.js';
11
-
12
- // Specialized: CSS State (for CSS variables and theme management)
13
- export { createCssState } from './cssState.js';
14
-
15
- // Utilities
16
- export { default as stateSerializer } from './stateSerializer.js';
17
- export { createTemplateManager } from './templateManager.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uistate/core",
3
- "version": "5.2.0",
3
+ "version": "5.4.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",
@@ -8,22 +8,16 @@
8
8
  ".": "./index.js",
9
9
  "./eventState": "./eventState.js",
10
10
  "./eventStateNew": "./eventStateNew.js",
11
- "./cssState": "./cssState.js",
12
- "./stateSerializer": "./stateSerializer.js",
13
- "./templateManager": "./templateManager.js"
11
+ "./query": "./queryClient.js"
14
12
  },
15
13
  "files": [
16
14
  "index.js",
17
15
  "eventState.js",
18
16
  "eventStateNew.js",
19
- "cssState.js",
20
- "stateSerializer.js",
21
- "templateManager.js",
17
+ "queryClient.js",
22
18
  "eventTest.js",
23
19
  "LICENSE",
24
- "LICENSE-eventTest.md",
25
- "examples/",
26
- "playground/"
20
+ "LICENSE-eventTest.md"
27
21
  ],
28
22
  "keywords": [
29
23
  "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
+ };
package/cssState.js DELETED
@@ -1,212 +0,0 @@
1
- /**
2
- * UIstate - CSS-based state management module with integrated serialization
3
- * Part of the UIstate declarative state management system
4
- * Uses CSS custom properties and data attributes for state representation
5
- * Features modular extension capabilities for DOM binding and events
6
- */
7
- import StateSerializer from './stateSerializer.js';
8
-
9
- const createCssState = (initialState = {}, serializer = StateSerializer) => {
10
- const state = {
11
- _sheet: null,
12
- _observers: new Map(),
13
- _serializer: serializer,
14
- _specialHandlers: {},
15
- _eventHandlers: new Map(), // Store custom event binding handlers
16
-
17
- init(serializerConfig) {
18
- if (!this._sheet) {
19
- const style = document.createElement('style');
20
- document.head.appendChild(style);
21
- this._sheet = style.sheet;
22
- this._addRule(':root {}');
23
- }
24
-
25
- // Configure serializer if options provided
26
- if (serializerConfig && typeof serializerConfig === 'object') {
27
- this._serializer.configure(serializerConfig);
28
- }
29
-
30
- // Initialize with any provided state
31
- if (initialState && typeof initialState === 'object') {
32
- Object.entries(initialState).forEach(([key, value]) => {
33
- this.setState(key, value);
34
- });
35
- }
36
-
37
- return this;
38
- },
39
-
40
- setState(key, value) {
41
- // Use serializer for CSS variables
42
- const cssValue = this._serializer.serialize(key, value);
43
- document.documentElement.style.setProperty(`--${key}`, cssValue);
44
-
45
- // Use serializer to handle all attribute application consistently
46
- this._serializer.applyToAttributes(key, value);
47
-
48
- // Notify any registered observers of the state change
49
- this._notifyObservers(key, value);
50
- return value;
51
- },
52
-
53
- setStates(stateObject) {
54
- Object.entries(stateObject).forEach(([key, value]) => {
55
- this.setState(key, value);
56
- });
57
- return this;
58
- },
59
-
60
- getState(key) {
61
- const value = getComputedStyle(document.documentElement).getPropertyValue(`--${key}`).trim();
62
- if (!value) return '';
63
-
64
- // Use serializer for deserialization
65
- return this._serializer.deserialize(key, value);
66
- },
67
-
68
- observe(key, callback) {
69
- if (!this._observers.has(key)) {
70
- this._observers.set(key, new Set());
71
- }
72
- this._observers.get(key).add(callback);
73
- return () => {
74
- const observers = this._observers.get(key);
75
- if (observers) {
76
- observers.delete(callback);
77
- }
78
- };
79
- },
80
-
81
- _notifyObservers(key, value) {
82
- const observers = this._observers.get(key);
83
- if (observers) {
84
- observers.forEach(cb => cb(value));
85
- }
86
- },
87
-
88
- registerSpecialHandler(stateKey, handlerFn) {
89
- this._specialHandlers[stateKey] = handlerFn;
90
- return this;
91
- },
92
-
93
- // New method for registering event bindings
94
- registerEventBinding(eventType, handler) {
95
- this._eventHandlers.set(eventType, handler);
96
- return this;
97
- },
98
-
99
- setupObservers(container = document) {
100
- container.querySelectorAll('[data-observe]:not([data-observing])').forEach(el => {
101
- const stateKey = el.dataset.observe;
102
-
103
- this.observe(stateKey, (value) => {
104
- // Special handlers should run first to set data-state
105
- if (this._specialHandlers[stateKey]?.observe) {
106
- this._specialHandlers[stateKey].observe(value, el);
107
- } else if (stateKey.endsWith('-state') && el.hasAttribute('data-state')) {
108
- // Only update data-state for elements that already have this attribute
109
- el.dataset.state = value;
110
- } else {
111
- // For normal state observers like theme, counter, etc.
112
- el.textContent = value;
113
- }
114
- });
115
-
116
- // Trigger initial state
117
- const initialValue = this.getState(stateKey);
118
- if (this._specialHandlers[stateKey]?.observe) {
119
- this._specialHandlers[stateKey].observe(initialValue, el);
120
- } else if (stateKey.endsWith('-state') && el.hasAttribute('data-state')) {
121
- // Only set data-state for elements that should have this attribute
122
- el.dataset.state = initialValue;
123
- } else {
124
- // For normal elements
125
- el.textContent = initialValue;
126
- }
127
-
128
- el.dataset.observing = 'true';
129
- });
130
-
131
- return this;
132
- },
133
-
134
- // Default event handlers available for implementations to use
135
- defaultClickHandler(e) {
136
- const target = e.target.closest('[data-state-action]');
137
- if (!target) return;
138
-
139
- const stateAction = target.dataset.stateAction;
140
- if (!stateAction) return;
141
-
142
- // Special handlers get first priority
143
- if (this._specialHandlers[stateAction]?.action) {
144
- this._specialHandlers[stateAction].action(target);
145
- return;
146
- }
147
-
148
- // Handle direct value setting via data-state-value
149
- if (target.dataset.stateValue !== undefined) {
150
- const valueToSet = target.dataset.stateValue;
151
- this.setState(stateAction, valueToSet);
152
- }
153
- },
154
-
155
- defaultInputHandler(e) {
156
- const target = e.target;
157
- const stateAction = target.dataset.stateAction;
158
-
159
- if (!stateAction) return;
160
-
161
- // Special handlers should access any needed data directly from the target
162
- if (this._specialHandlers[stateAction]?.action) {
163
- this._specialHandlers[stateAction].action(target);
164
- }
165
- },
166
-
167
- // Updated setupStateActions to use registered event handlers
168
- setupStateActions(container = document) {
169
- // Only bind the registered event types
170
- this._eventHandlers.forEach((handler, eventType) => {
171
- container.addEventListener(eventType, handler);
172
- });
173
-
174
- // If no event handlers registered, register the default ones
175
- if (this._eventHandlers.size === 0) {
176
- container.addEventListener('click', (e) => this.defaultClickHandler(e));
177
- container.addEventListener('input', (e) => this.defaultInputHandler(e));
178
- }
179
-
180
- return this;
181
- },
182
-
183
- _addRule(rule) {
184
- if (this._sheet) {
185
- this._sheet.insertRule(rule, this._sheet.cssRules.length);
186
- }
187
- },
188
-
189
- // Add serializer configuration method
190
- configureSerializer(config) {
191
- if (this._serializer.configure) {
192
- this._serializer.configure(config);
193
- }
194
- return this;
195
- },
196
-
197
- // Clean up resources
198
- destroy() {
199
- this._observers.clear();
200
- // The style element will remain in the DOM
201
- // as removing it would affect the UI state
202
- }
203
- };
204
-
205
- return state.init();
206
- };
207
-
208
- // Create a singleton instance for easy usage
209
- const UIstate = createCssState();
210
-
211
- export { createCssState };
212
- export default UIstate;
@@ -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>