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