@uistate/core 5.1.1 → 5.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (139) hide show
  1. package/eventStateNew.js +8 -2
  2. package/package.json +5 -5
  3. package/queryClient.js +55 -0
  4. package/examples/001-counter/README.md +0 -44
  5. package/examples/001-counter/index.html +0 -33
  6. package/examples/002-counter-improved/README.md +0 -44
  7. package/examples/002-counter-improved/index.html +0 -47
  8. package/examples/003-input-reactive/README.md +0 -44
  9. package/examples/003-input-reactive/index.html +0 -33
  10. package/examples/004-computed-state/README.md +0 -45
  11. package/examples/004-computed-state/index.html +0 -65
  12. package/examples/005-conditional-rendering/README.md +0 -42
  13. package/examples/005-conditional-rendering/index.html +0 -39
  14. package/examples/006-list-rendering/README.md +0 -49
  15. package/examples/006-list-rendering/index.html +0 -63
  16. package/examples/007-form-validation/README.md +0 -52
  17. package/examples/007-form-validation/index.html +0 -102
  18. package/examples/008-undo-redo/README.md +0 -70
  19. package/examples/008-undo-redo/index.html +0 -108
  20. package/examples/009-localStorage-side-effects/README.md +0 -72
  21. package/examples/009-localStorage-side-effects/index.html +0 -57
  22. package/examples/010-decoupled-components/README.md +0 -74
  23. package/examples/010-decoupled-components/index.html +0 -93
  24. package/examples/011-async-patterns/README.md +0 -98
  25. package/examples/011-async-patterns/index.html +0 -132
  26. package/examples/028-counter-improved-eventTest/LICENSE +0 -55
  27. package/examples/028-counter-improved-eventTest/README.md +0 -131
  28. package/examples/028-counter-improved-eventTest/app/store.js +0 -9
  29. package/examples/028-counter-improved-eventTest/index.html +0 -49
  30. package/examples/028-counter-improved-eventTest/runtime/core/behaviors.runtime.js +0 -282
  31. package/examples/028-counter-improved-eventTest/runtime/core/eventState.js +0 -100
  32. package/examples/028-counter-improved-eventTest/runtime/core/eventStateNew.js +0 -149
  33. package/examples/028-counter-improved-eventTest/runtime/core/helpers.js +0 -212
  34. package/examples/028-counter-improved-eventTest/runtime/core/router.js +0 -271
  35. package/examples/028-counter-improved-eventTest/store.d.ts +0 -8
  36. package/examples/028-counter-improved-eventTest/style.css +0 -170
  37. package/examples/028-counter-improved-eventTest/tests/README.md +0 -208
  38. package/examples/028-counter-improved-eventTest/tests/counter.test.js +0 -116
  39. package/examples/028-counter-improved-eventTest/tests/eventTest.js +0 -176
  40. package/examples/028-counter-improved-eventTest/tests/generateTypes.js +0 -168
  41. package/examples/028-counter-improved-eventTest/tests/run.js +0 -20
  42. package/examples/030-todo-app-with-eventTest/LICENSE +0 -55
  43. package/examples/030-todo-app-with-eventTest/README.md +0 -121
  44. package/examples/030-todo-app-with-eventTest/app/router.js +0 -25
  45. package/examples/030-todo-app-with-eventTest/app/store.js +0 -16
  46. package/examples/030-todo-app-with-eventTest/app/views/home.js +0 -11
  47. package/examples/030-todo-app-with-eventTest/app/views/todoDemo.js +0 -88
  48. package/examples/030-todo-app-with-eventTest/index.html +0 -65
  49. package/examples/030-todo-app-with-eventTest/runtime/core/behaviors.runtime.js +0 -282
  50. package/examples/030-todo-app-with-eventTest/runtime/core/eventState.js +0 -100
  51. package/examples/030-todo-app-with-eventTest/runtime/core/eventStateNew.js +0 -149
  52. package/examples/030-todo-app-with-eventTest/runtime/core/helpers.js +0 -212
  53. package/examples/030-todo-app-with-eventTest/runtime/core/router.js +0 -271
  54. package/examples/030-todo-app-with-eventTest/store.d.ts +0 -18
  55. package/examples/030-todo-app-with-eventTest/style.css +0 -170
  56. package/examples/030-todo-app-with-eventTest/tests/README.md +0 -208
  57. package/examples/030-todo-app-with-eventTest/tests/eventTest.js +0 -176
  58. package/examples/030-todo-app-with-eventTest/tests/generateTypes.js +0 -189
  59. package/examples/030-todo-app-with-eventTest/tests/run.js +0 -20
  60. package/examples/030-todo-app-with-eventTest/tests/todos.test.js +0 -167
  61. package/examples/031-todo-app-with-eventTest/LICENSE +0 -55
  62. package/examples/031-todo-app-with-eventTest/README.md +0 -54
  63. package/examples/031-todo-app-with-eventTest/TUTORIAL.md +0 -390
  64. package/examples/031-todo-app-with-eventTest/WHY_EVENTSTATE.md +0 -777
  65. package/examples/031-todo-app-with-eventTest/app/bridges.js +0 -113
  66. package/examples/031-todo-app-with-eventTest/app/router.js +0 -26
  67. package/examples/031-todo-app-with-eventTest/app/store.js +0 -15
  68. package/examples/031-todo-app-with-eventTest/app/views/home.js +0 -46
  69. package/examples/031-todo-app-with-eventTest/app/views/todoDemo.js +0 -69
  70. package/examples/031-todo-app-with-eventTest/devtools/dock.js +0 -41
  71. package/examples/031-todo-app-with-eventTest/devtools/stateTracker.dock.js +0 -10
  72. package/examples/031-todo-app-with-eventTest/devtools/stateTracker.js +0 -246
  73. package/examples/031-todo-app-with-eventTest/devtools/telemetry.js +0 -104
  74. package/examples/031-todo-app-with-eventTest/devtools/typeGenerator.js +0 -339
  75. package/examples/031-todo-app-with-eventTest/index.html +0 -103
  76. package/examples/031-todo-app-with-eventTest/package-lock.json +0 -2184
  77. package/examples/031-todo-app-with-eventTest/package.json +0 -24
  78. package/examples/031-todo-app-with-eventTest/runtime/core/behaviors.runtime.js +0 -282
  79. package/examples/031-todo-app-with-eventTest/runtime/core/eventState.js +0 -100
  80. package/examples/031-todo-app-with-eventTest/runtime/core/eventStateNew.js +0 -149
  81. package/examples/031-todo-app-with-eventTest/runtime/core/helpers.js +0 -212
  82. package/examples/031-todo-app-with-eventTest/runtime/core/router.js +0 -271
  83. package/examples/031-todo-app-with-eventTest/runtime/extensions/boundary.js +0 -36
  84. package/examples/031-todo-app-with-eventTest/runtime/extensions/converge.js +0 -63
  85. package/examples/031-todo-app-with-eventTest/runtime/extensions/eventState.plus.js +0 -210
  86. package/examples/031-todo-app-with-eventTest/runtime/extensions/hydrate.js +0 -157
  87. package/examples/031-todo-app-with-eventTest/runtime/extensions/queryBinding.js +0 -69
  88. package/examples/031-todo-app-with-eventTest/runtime/forms/computed.js +0 -78
  89. package/examples/031-todo-app-with-eventTest/runtime/forms/meta.js +0 -51
  90. package/examples/031-todo-app-with-eventTest/runtime/forms/submitWithBoundary.js +0 -28
  91. package/examples/031-todo-app-with-eventTest/runtime/forms/validators.js +0 -55
  92. package/examples/031-todo-app-with-eventTest/store.d.ts +0 -23
  93. package/examples/031-todo-app-with-eventTest/style.css +0 -170
  94. package/examples/031-todo-app-with-eventTest/tests/README.md +0 -208
  95. package/examples/031-todo-app-with-eventTest/tests/eventTest.js +0 -176
  96. package/examples/031-todo-app-with-eventTest/tests/generateTypes.js +0 -191
  97. package/examples/031-todo-app-with-eventTest/tests/run.js +0 -20
  98. package/examples/031-todo-app-with-eventTest/tests/todos.test.js +0 -192
  99. package/examples/032-todo-app-with-eventTest/LICENSE +0 -55
  100. package/examples/032-todo-app-with-eventTest/README.md +0 -54
  101. package/examples/032-todo-app-with-eventTest/TUTORIAL.md +0 -390
  102. package/examples/032-todo-app-with-eventTest/WHY_EVENTSTATE.md +0 -777
  103. package/examples/032-todo-app-with-eventTest/app/actions/index.js +0 -153
  104. package/examples/032-todo-app-with-eventTest/app/bridges.js +0 -113
  105. package/examples/032-todo-app-with-eventTest/app/router.js +0 -26
  106. package/examples/032-todo-app-with-eventTest/app/store.js +0 -15
  107. package/examples/032-todo-app-with-eventTest/app/views/home.js +0 -46
  108. package/examples/032-todo-app-with-eventTest/app/views/todoDemo.js +0 -69
  109. package/examples/032-todo-app-with-eventTest/devtools/dock.js +0 -41
  110. package/examples/032-todo-app-with-eventTest/devtools/stateTracker.dock.js +0 -10
  111. package/examples/032-todo-app-with-eventTest/devtools/stateTracker.js +0 -246
  112. package/examples/032-todo-app-with-eventTest/devtools/telemetry.js +0 -104
  113. package/examples/032-todo-app-with-eventTest/devtools/typeGenerator.js +0 -339
  114. package/examples/032-todo-app-with-eventTest/index.html +0 -87
  115. package/examples/032-todo-app-with-eventTest/package-lock.json +0 -2184
  116. package/examples/032-todo-app-with-eventTest/package.json +0 -24
  117. package/examples/032-todo-app-with-eventTest/runtime/core/behaviors.runtime.js +0 -282
  118. package/examples/032-todo-app-with-eventTest/runtime/core/eventState.js +0 -100
  119. package/examples/032-todo-app-with-eventTest/runtime/core/eventStateNew.js +0 -149
  120. package/examples/032-todo-app-with-eventTest/runtime/core/helpers.js +0 -212
  121. package/examples/032-todo-app-with-eventTest/runtime/core/router.js +0 -271
  122. package/examples/032-todo-app-with-eventTest/runtime/extensions/boundary.js +0 -36
  123. package/examples/032-todo-app-with-eventTest/runtime/extensions/converge.js +0 -63
  124. package/examples/032-todo-app-with-eventTest/runtime/extensions/eventState.plus.js +0 -210
  125. package/examples/032-todo-app-with-eventTest/runtime/extensions/hydrate.js +0 -157
  126. package/examples/032-todo-app-with-eventTest/runtime/extensions/queryBinding.js +0 -69
  127. package/examples/032-todo-app-with-eventTest/runtime/forms/computed.js +0 -78
  128. package/examples/032-todo-app-with-eventTest/runtime/forms/meta.js +0 -51
  129. package/examples/032-todo-app-with-eventTest/runtime/forms/submitWithBoundary.js +0 -28
  130. package/examples/032-todo-app-with-eventTest/runtime/forms/validators.js +0 -55
  131. package/examples/032-todo-app-with-eventTest/store.d.ts +0 -23
  132. package/examples/032-todo-app-with-eventTest/style.css +0 -170
  133. package/examples/032-todo-app-with-eventTest/tests/README.md +0 -208
  134. package/examples/032-todo-app-with-eventTest/tests/eventTest.js +0 -176
  135. package/examples/032-todo-app-with-eventTest/tests/generateTypes.js +0 -191
  136. package/examples/032-todo-app-with-eventTest/tests/run.js +0 -20
  137. package/examples/032-todo-app-with-eventTest/tests/todos.test.js +0 -192
  138. package/playground/exercise001.html +0 -38
  139. package/playground/exercise002.html +0 -49
@@ -1,153 +0,0 @@
1
- // actions/index.js - minimal action registry (10 core ops)
2
- // Each action is a pure function: (ctx, ...args) => any
3
- // ctx: { store, get(path), set(path, value), event, el }
4
-
5
- export function set(ctx, path, value){
6
- ctx.set(String(path), value);
7
- }
8
-
9
- export function inc(ctx, path, by = 1){
10
- const v = Number(ctx.get(String(path)) || 0);
11
- ctx.set(String(path), v + Number(by));
12
- }
13
-
14
- export function dec(ctx, path, by = 1){
15
- const v = Number(ctx.get(String(path)) || 0);
16
- ctx.set(String(path), v - Number(by));
17
- }
18
-
19
- export function toggle(ctx, path){
20
- const v = !!ctx.get(String(path));
21
- ctx.set(String(path), !v);
22
- }
23
-
24
- export function clamp(ctx, path, min, max){
25
- let v = Number(ctx.get(String(path)) || 0);
26
- if (min != null) v = Math.max(v, Number(min));
27
- if (max != null) v = Math.min(v, Number(max));
28
- ctx.set(String(path), v);
29
- }
30
-
31
- export function push(ctx, path, value){
32
- const arr = Array.isArray(ctx.get(String(path))) ? ctx.get(String(path)) : [];
33
- ctx.set(String(path), [...arr, value]);
34
- }
35
-
36
- export function pushFrom(ctx, toArrayPath, fromPath){
37
- const arr = Array.isArray(ctx.get(String(toArrayPath))) ? ctx.get(String(toArrayPath)) : [];
38
- const v = ctx.get(String(fromPath));
39
- ctx.set(String(toArrayPath), [...arr, v]);
40
- }
41
-
42
- export function pushFromIfNotEmpty(ctx, toArrayPath, fromPath){
43
- const arr = Array.isArray(ctx.get(String(toArrayPath))) ? ctx.get(String(toArrayPath)) : [];
44
- let v = ctx.get(String(fromPath));
45
- if (v == null) return;
46
- v = String(v).trim();
47
- if (v.length === 0) return;
48
- ctx.set(String(toArrayPath), [...arr, v]);
49
- }
50
-
51
- export function removeAt(ctx, path, index){
52
- const arr = Array.isArray(ctx.get(String(path))) ? ctx.get(String(path)) : [];
53
- const i = Number(index);
54
- if (i >= 0 && i < arr.length){
55
- const next = arr.slice(0, i).concat(arr.slice(i + 1));
56
- ctx.set(String(path), next);
57
- }
58
- }
59
-
60
- export function pop(ctx, path){
61
- const arr = Array.isArray(ctx.get(String(path))) ? ctx.get(String(path)) : [];
62
- if (arr.length === 0) return;
63
- ctx.set(String(path), arr.slice(0, -1));
64
- }
65
-
66
- export function sortBy(ctx, path, key){
67
- const arr = Array.isArray(ctx.get(String(path))) ? ctx.get(String(path)) : [];
68
- let next;
69
- if (key == null || key === ''){
70
- next = [...arr].sort();
71
- } else {
72
- next = [...arr].sort((a,b) => {
73
- const av = a?.[key]; const bv = b?.[key];
74
- if (av < bv) return -1; if (av > bv) return 1; return 0;
75
- });
76
- }
77
- ctx.set(String(path), next);
78
- }
79
-
80
- export function lengthTo(ctx, fromPath, toPath){
81
- const v = ctx.get(String(fromPath));
82
- const len = Array.isArray(v) || typeof v === 'string' ? v.length : (v && typeof v === 'object' ? Object.keys(v).length : 0);
83
- ctx.set(String(toPath), len);
84
- }
85
-
86
- export function setFrom(ctx, path, eventField){
87
- // eventField like 'target.value' or 'detail.value'
88
- let cur = ctx.event;
89
- for (const part of String(eventField).split('.')){
90
- if (cur == null) break;
91
- cur = cur[part];
92
- }
93
- ctx.set(String(path), cur);
94
- }
95
-
96
- export function fetchJson(ctx, url, toPath){
97
- // minimal fire-and-forget; caller can chain a separate set if desired
98
- fetch(String(url), { signal: ctx.event?.signal }).then(r => r.json()).then(data => {
99
- if (toPath) ctx.set(String(toPath), data);
100
- }).catch(() => {});
101
- }
102
-
103
- // Demo-only: mutate the global behaviors whitelist array (shared by installer)
104
- export function guardWhitelist(ctx, ...patterns){
105
- const arr = (window && window.behaviorsWhitelist) || [];
106
- arr.splice(0, arr.length, ...patterns.map(String));
107
- try { ctx.set('ui.guard.whitelist', patterns.map(String)); } catch {}
108
- }
109
-
110
- export function clearWhitelist(){
111
- const arr = (window && window.behaviorsWhitelist) || [];
112
- arr.splice(0, arr.length);
113
- try { window.stateTrackerStore?.set?.('ui.guard.whitelist', []); } catch {}
114
- }
115
-
116
- export function resetWhitelist(){
117
- const def = (window && window.behaviorsWhitelistDefault) || [];
118
- const arr = (window && window.behaviorsWhitelist) || [];
119
- arr.splice(0, arr.length, ...def.map(String));
120
- try { window.stateTrackerStore?.set?.('ui.guard.whitelist', [...def]); } catch {}
121
- }
122
-
123
- export function mergeWhitelist(ctx, ...patterns){
124
- const arr = (window && window.behaviorsWhitelist) || [];
125
- const set = new Set(arr.map(String));
126
- patterns.map(String).forEach(p => set.add(p));
127
- const next = Array.from(set);
128
- arr.splice(0, arr.length, ...next);
129
- try { window.stateTrackerStore?.set?.('ui.guard.whitelist', [...next]); } catch {}
130
- }
131
-
132
- export function toggleTheme(ctx){
133
- try {
134
- const cur = ctx.get('ui.theme');
135
- const next = (cur === 'dark') ? 'light' : 'dark';
136
- ctx.set('ui.theme', next);
137
- console.log('[beh] theme ->', next);
138
- } catch {}
139
- }
140
-
141
- // Diagnostics
142
- export function log(ctx, ...args){
143
- try { console.log('[beh]', ...args); } catch {}
144
- }
145
-
146
- export function logPath(ctx, path){
147
- try { console.log('[beh]', String(path), ctx.get(String(path))); } catch {}
148
- }
149
-
150
- export const registry = {
151
- set, inc, dec, toggle, clamp, push, pushFrom, pushFromIfNotEmpty, removeAt, pop, sortBy, setFrom, fetchJson, lengthTo,
152
- guardWhitelist, clearWhitelist, resetWhitelist, mergeWhitelist, toggleTheme, log, logPath,
153
- };
@@ -1,113 +0,0 @@
1
- // bridges.app.js
2
- // App-level intent → domain bridges and derived wildcard bridges
3
- // Mirrors patterns proven in examples 300d (intent bridge) and 300e (derived wildcard).
4
-
5
- import store from './store.js';
6
-
7
- // ------------------------------
8
- // Selection: intent → domain
9
- // ------------------------------
10
- store.subscribe('intent.selection.toggle', (payload) => {
11
- const cur = store.get('ui.selection.ids') || [];
12
- const set = new Set(Array.isArray(cur) ? cur : []);
13
- let id, checked;
14
- if (payload && typeof payload === 'object') { id = payload.id; checked = payload.checked; }
15
- else { id = payload; checked = undefined; }
16
- const key = String(id);
17
- if (checked === undefined) {
18
- // toggle membership
19
- if (set.has(key)) set.delete(key); else set.add(key);
20
- } else {
21
- if (checked) set.add(key); else set.delete(key);
22
- }
23
- const next = Array.from(set);
24
- store.set('ui.selection.ids', next);
25
- });
26
-
27
- // Derived: selection count
28
- store.subscribe('ui.selection.ids', () => {
29
- const ids = store.get('ui.selection.ids') || [];
30
- const next = Array.isArray(ids) ? ids.length : 0;
31
- if (store.get('ui.selection.count') !== next) store.set('ui.selection.count', next);
32
- });
33
-
34
- // ------------------------------
35
- // Quotes: async fetch with last-request-wins
36
- // ------------------------------
37
- let quotesReqId = 0;
38
- store.subscribe('intent.quotes.load', ({ url, ttlMs }) => {
39
- quotesReqId += 1;
40
- const myId = quotesReqId;
41
- store.set('ui.quotes.loading', true);
42
- store.set('ui.quotes.error', null);
43
-
44
- const doFetch = (globalThis.fetch ? globalThis.fetch(String(url)) : Promise.reject(new Error('fetch unavailable')));
45
- doFetch
46
- .then(async (res) => {
47
- if (myId !== quotesReqId) return; // stale
48
- if (!res.ok) throw new Error('HTTP ' + (res.status || 'error'));
49
- const data = await res.json();
50
- store.set('ui.quotes.data', data);
51
- })
52
- .catch((err) => {
53
- if (myId !== quotesReqId) return; // stale
54
- store.set('ui.quotes.error', String(err && err.message || err));
55
- })
56
- .finally(() => {
57
- if (myId !== quotesReqId) return; // stale
58
- store.set('ui.quotes.loading', false);
59
- });
60
- });
61
-
62
- // Derived: quotes empty
63
- const updateQuotesEmpty = () => {
64
- const d = store.get('ui.quotes?.data') ?? store.get('ui.quotes.data');
65
- const empty = Array.isArray(d) ? d.length === 0 : (d == null);
66
- if (store.get('ui.quotes.empty') !== empty) store.set('ui.quotes.empty', empty);
67
- };
68
- store.subscribe('ui.quotes.data', updateQuotesEmpty);
69
- store.subscribe('ui.quotes.error', updateQuotesEmpty);
70
-
71
- // ------------------------------
72
- // Items: derived helpers for repeaters
73
- // ------------------------------
74
- const updateItemsMeta = () => {
75
- const items = store.get('ui.items');
76
- const count = Array.isArray(items) ? items.length : 0;
77
- if (store.get('ui.itemsCount') !== count) store.set('ui.itemsCount', count);
78
- const empty = count === 0;
79
- if (store.get('ui.empty') !== empty) store.set('ui.empty', empty);
80
- };
81
- store.subscribe('ui.items', updateItemsMeta);
82
- try { updateItemsMeta(); } catch {}
83
-
84
- // ------------------------------
85
- // Todos: imperative renderer-friendly bridges
86
- // ------------------------------
87
- // Add todo
88
- store.subscribe('intent.todo.add', ({ text }) => {
89
- const items = store.get('domain.todos.items') || [];
90
- const nextId = items.reduce((m, t) => Math.max(m, Number(t?.id || 0)), 0) + 1;
91
- const todo = { id: nextId, text: String(text || '').trim(), done: false };
92
- if (!todo.text) return;
93
- store.set('domain.todos.items', [...items, todo]);
94
- });
95
-
96
- // Toggle todo
97
- store.subscribe('intent.todo.toggle', ({ id }) => {
98
- const items = store.get('domain.todos.items') || [];
99
- const out = items.map(t => (String(t?.id) === String(id)) ? { ...t, done: !t.done } : t);
100
- store.set('domain.todos.items', out);
101
- });
102
-
103
- // Clear completed
104
- store.subscribe('intent.todo.clearCompleted', () => {
105
- const items = store.get('domain.todos.items') || [];
106
- store.set('domain.todos.items', items.filter(t => !t.done));
107
- });
108
-
109
- // UI filter
110
- store.subscribe('intent.ui.filter', ({ filter }) => {
111
- const f = (filter === 'active' || filter === 'completed') ? filter : 'all';
112
- store.set('ui.todos.filter', f);
113
- });
@@ -1,26 +0,0 @@
1
- // app/router.js — App-specific router configuration
2
- import { createRouter } from '../runtime/core/router.js';
3
- import { upgradeEventState } from '../runtime/extensions/eventState.plus.js';
4
- import store from './store.js';
5
- import * as Home from './views/home.js';
6
- import * as TodoDemo from './views/todoDemo.js';
7
-
8
- // Upgrade store for setMany support
9
- const storePlus = upgradeEventState(store);
10
-
11
- // Create and start router
12
- const router = createRouter({
13
- routes: [
14
- { path: '/', view: 'home', component: Home },
15
- { path: '/todo-demo', view: 'todo-demo', component: TodoDemo },
16
- ],
17
- store: storePlus,
18
- rootSelector: '[data-route-root]',
19
- fallback: { path: '/', view: 'home', component: Home },
20
- debug: import.meta?.env?.DEV || false,
21
- });
22
-
23
- router.start();
24
-
25
- // Export router API
26
- export const { navigate, navigateQuery, navigatePath } = router;
@@ -1,15 +0,0 @@
1
- // store.js — singleton eventState store for the SPA
2
- import { createEventState } from '../runtime/core/eventStateNew.js';
3
-
4
- const initial = {
5
- ui: {
6
- route: { path: '/', view: 'home', params: {}, query: {}, transitioning: false },
7
- todos: { filter: 'all' },
8
- },
9
- domain: {
10
- todos: { items: [] },
11
- },
12
- };
13
-
14
- const store = createEventState(initial);
15
- export default store;
@@ -1,46 +0,0 @@
1
- // views/home.js — Home route
2
- export async function boot({ store, el, signal }){
3
- // Artificial 1-second delay to show the loader
4
- await new Promise(resolve => setTimeout(resolve, 1000));
5
-
6
- const container = document.createElement('main');
7
- container.style.cssText = 'max-width: 600px; margin: 2rem auto; padding: 0 1rem;';
8
- container.innerHTML = `
9
- <h1>Home works!</h1>
10
- <p>This is the home page of the todo app example.</p>
11
- <p><a href="/todo-demo" data-link>Go to Todo App Demo →</a></p>
12
-
13
- <hr style="margin: 2rem 0;">
14
-
15
- <h2>Telemetry Test</h2>
16
- <p>Counter: <strong id="counter-display">0</strong></p>
17
- <button id="increment-btn" class="btn">Increment Counter</button>
18
- `;
19
- el.appendChild(container);
20
-
21
- // Initialize counter in store
22
- if (store.get('ui.test.counter') === undefined) {
23
- store.set('ui.test.counter', 0);
24
- }
25
-
26
- // Counter display subscription
27
- const counterDisplay = container.querySelector('#counter-display');
28
- const updateDisplay = () => {
29
- const count = store.get('ui.test.counter') || 0;
30
- counterDisplay.textContent = count;
31
- };
32
- const unsub = store.subscribe('ui.test.counter', updateDisplay);
33
- updateDisplay();
34
-
35
- // Increment button
36
- const incrementBtn = container.querySelector('#increment-btn');
37
- incrementBtn.addEventListener('click', () => {
38
- const current = store.get('ui.test.counter') || 0;
39
- console.log('[TEST] Incrementing counter from', current, 'to', current + 1);
40
- store.set('ui.test.counter', current + 1);
41
- });
42
-
43
- // Cleanup on navigation
44
- if (signal) signal.addEventListener('abort', () => { unsub(); });
45
- return () => { unsub(); };
46
- }
@@ -1,69 +0,0 @@
1
- // views/todoDemo.js — Minimal Todo app demo (imperative renderer, no bootstrap)
2
- export async function boot({ store, el, signal }){
3
- const main = document.createElement('main');
4
- main.innerHTML = `
5
- <h1>Todo app demo</h1>
6
- <section class="beh-section">
7
- <div style="display:flex; gap:8px; align-items:center; flex-wrap:wrap">
8
- <input id="newTodo" placeholder="New todo" />
9
- <button id="addTodo" class="btn">Add</button>
10
- <div style="display:flex; gap:6px; align-items:center">
11
- <button id="fAll" class="btn">All</button>
12
- <button id="fActive" class="btn">Active</button>
13
- <button id="fCompleted" class="btn">Completed</button>
14
- <button id="clearCompleted" class="btn" style="background:#b91c1c; color:white">Clear Completed</button>
15
- </div>
16
- <span id="filterBadge" style="padding:2px 6px; border:1px solid #888; border-radius:8px; font-size:.85em; color:#555">filter: all</span>
17
- </div>
18
- <ul id="todos" style="margin-top:10px; padding-left: 18px;"></ul>
19
- </section>
20
- `;
21
- el.appendChild(main);
22
-
23
- const input = main.querySelector('#newTodo');
24
- const ul = main.querySelector('#todos');
25
- const btnAdd = main.querySelector('#addTodo');
26
- const btnAll = main.querySelector('#fAll');
27
- const btnAct = main.querySelector('#fActive');
28
- const btnDone = main.querySelector('#fCompleted');
29
- const btnClear = main.querySelector('#clearCompleted');
30
-
31
- // Intents from UI
32
- btnAdd?.addEventListener('click', () => {
33
- const text = (input?.value || '').trim();
34
- if (!text) return; store.set('intent.todo.add', { text }); input.value = '';
35
- });
36
- input?.addEventListener('keydown', (e) => { if (e.key === 'Enter') btnAdd?.click(); });
37
- btnAll?.addEventListener('click', () => store.set('intent.ui.filter', { filter: 'all' }));
38
- btnAct?.addEventListener('click', () => store.set('intent.ui.filter', { filter: 'active' }));
39
- btnDone?.addEventListener('click', () => store.set('intent.ui.filter', { filter: 'completed' }));
40
- btnClear?.addEventListener('click', () => store.set('intent.todo.clearCompleted'));
41
-
42
- // Render
43
- const itemsPath = 'domain.todos.items';
44
- const filterPath = 'ui.todos.filter';
45
- function render(){
46
- const items = store.get(itemsPath) || [];
47
- const filter = store.get(filterPath) || 'all';
48
- const badge = main.querySelector('#filterBadge');
49
- if (badge) badge.textContent = `filter: ${filter}`;
50
- ul.replaceChildren();
51
- let rows = items;
52
- if (filter === 'active') rows = items.filter(t => !t.done);
53
- else if (filter === 'completed') rows = items.filter(t => !!t.done);
54
- rows.forEach((t) => {
55
- const li = document.createElement('li');
56
- li.style.display = 'flex'; li.style.gap = '8px'; li.style.alignItems = 'center';
57
- const cb = document.createElement('input'); cb.type = 'checkbox'; cb.checked = !!t.done;
58
- cb.addEventListener('change', () => store.set('intent.todo.toggle', { id: t.id }));
59
- const span = document.createElement('span'); span.textContent = t.text; if (t.done) span.style.textDecoration = 'line-through';
60
- li.appendChild(cb); li.appendChild(span); ul.appendChild(li);
61
- });
62
- }
63
- const off1 = store.subscribe(itemsPath, render);
64
- const off2 = store.subscribe(filterPath, render);
65
- render();
66
-
67
- if (signal) signal.addEventListener('abort', () => { try { off1 && off1(); off2 && off2(); } catch {} });
68
- return () => { try { off1 && off1(); off2 && off2(); } catch {} };
69
- }
@@ -1,41 +0,0 @@
1
- // dev-dock.dev.js — shared dev dock for buttons (DEV only)
2
- // if (import.meta && import.meta.env && import.meta.env.DEV) {
3
- const DOCK_ID = 'dev-dock-root';
4
- const STYLE_ID = 'dev-dock-style';
5
- const CSS = `
6
- #${DOCK_ID} { position: fixed; left: 10px; bottom: 10px; z-index: 2147483200; pointer-events: auto;
7
- display: inline-flex; flex-direction: row; gap: 6px; align-items: center; background: rgba(17,17,17,.85);
8
- border: 1px solid rgba(255,255,255,.12); border-radius: 10px; padding: 6px; box-shadow: 0 2px 10px rgba(0,0,0,.25); }
9
- #${DOCK_ID} .dock-btn { appearance: none; border: 1px solid rgba(255,255,255,.15); background: #222; color: #eee;
10
- font: 600 12px/1 system-ui, -apple-system, Segoe UI, Roboto, sans-serif; border-radius: 8px; padding: 6px 10px; cursor: pointer; }
11
- #${DOCK_ID} .dock-btn:hover { background: #2a2a2a; }
12
- #${DOCK_ID} > button { cursor: pointer; }
13
- #${DOCK_ID} .dock-sep { width: 1px; height: 18px; background: rgba(255,255,255,.12); margin: 0 4px; }
14
- `;
15
-
16
- // Style
17
- let style = document.getElementById(STYLE_ID);
18
- if (!style){ style = document.createElement('style'); style.id = STYLE_ID; style.textContent = CSS; document.head.appendChild(style); }
19
-
20
- // Root
21
- let root = document.getElementById(DOCK_ID);
22
- if (!root){ root = document.createElement('div'); root.id = DOCK_ID; document.body.appendChild(root); }
23
-
24
- const registry = new Map();
25
- function register({ id, label, title = '', onClick }){
26
- // De-dup by id (helps during HMR)
27
- try { const exist = root.querySelector(`[data-dock-id="${id}"]`); if (exist) exist.remove(); } catch {}
28
- const btn = document.createElement('button');
29
- btn.type = 'button'; btn.className = 'dock-btn'; btn.textContent = label; if (title) btn.title = title;
30
- btn.setAttribute('data-dock-id', id);
31
- btn.addEventListener('click', (e) => { try { onClick?.(e); } catch (err) { console.warn('[dev-dock] button error', err); } });
32
- root.appendChild(btn);
33
- registry.set(id, btn);
34
- return () => { try { btn.remove(); } catch{}; registry.delete(id); };
35
- }
36
- function separator(){ const sep = document.createElement('div'); sep.className = 'dock-sep'; root.appendChild(sep); return () => sep.remove(); }
37
-
38
- window.__devdock = { register, separator, root };
39
- // Notify listeners that the dock is ready
40
- try { window.dispatchEvent(new CustomEvent('devdock:ready')); } catch {}
41
- // }
@@ -1,10 +0,0 @@
1
- // stateTracker.dock.dev.js — register a State toggle in dev dock and hide pill (DEV only)
2
- // if (import.meta && import.meta.env && import.meta.env.DEV) {
3
- const st = window.stateTracker?.instance;
4
- const dock = window.__devdock;
5
- if (dock && st) {
6
- // Hide the pill; dev dock becomes the control surface
7
- try { st.elements?.pill?.style && (st.elements.pill.style.display = 'none'); } catch {}
8
- dock.register({ id: 'state-tracker', label: 'State', title: 'Toggle State Tracker', onClick: () => st.toggle() });
9
- }
10
- // }