@jsenv/navi 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (123) hide show
  1. package/index.js +51 -0
  2. package/package.json +38 -0
  3. package/src/action_private_properties.js +11 -0
  4. package/src/action_proxy_test.html +353 -0
  5. package/src/action_run_states.js +5 -0
  6. package/src/actions.js +1377 -0
  7. package/src/browser_integration/browser_integration.js +191 -0
  8. package/src/browser_integration/document_back_and_forward.js +17 -0
  9. package/src/browser_integration/document_loading_signal.js +100 -0
  10. package/src/browser_integration/document_state_signal.js +9 -0
  11. package/src/browser_integration/document_url_signal.js +9 -0
  12. package/src/browser_integration/use_is_visited.js +19 -0
  13. package/src/browser_integration/via_history.js +199 -0
  14. package/src/browser_integration/via_navigation.js +168 -0
  15. package/src/components/action_execution/form_context.js +8 -0
  16. package/src/components/action_execution/render_actionable_component.jsx +27 -0
  17. package/src/components/action_execution/use_action.js +330 -0
  18. package/src/components/action_execution/use_execute_action.js +161 -0
  19. package/src/components/action_renderer.jsx +136 -0
  20. package/src/components/collect_form_element_values.js +79 -0
  21. package/src/components/demos/0_button_demo.html +155 -0
  22. package/src/components/demos/1_checkbox_demo.html +257 -0
  23. package/src/components/demos/2_input_textual_demo.html +354 -0
  24. package/src/components/demos/3_radio_demo.html +222 -0
  25. package/src/components/demos/4_select_demo.html +104 -0
  26. package/src/components/demos/5_list_scrollable_demo.html +153 -0
  27. package/src/components/demos/action/0_button_demo.html +204 -0
  28. package/src/components/demos/action/10_shortcuts_demo.html +189 -0
  29. package/src/components/demos/action/11_nested_shortcuts_demo.html +401 -0
  30. package/src/components/demos/action/1_input_text_demo.html +461 -0
  31. package/src/components/demos/action/2_form_multiple.html +303 -0
  32. package/src/components/demos/action/3_details_demo.html +172 -0
  33. package/src/components/demos/action/4_input_checkbox_demo.html +611 -0
  34. package/src/components/demos/action/6_checkbox_list_demo.html +109 -0
  35. package/src/components/demos/action/7_radio_list_demo.html +217 -0
  36. package/src/components/demos/action/8_editable_text_demo.html +442 -0
  37. package/src/components/demos/action/9_link_demo.html +172 -0
  38. package/src/components/demos/demo.md +0 -0
  39. package/src/components/demos/route/basic/basic.html +14 -0
  40. package/src/components/demos/route/basic/basic_route_demo.jsx +224 -0
  41. package/src/components/demos/route/multi/multi.html +14 -0
  42. package/src/components/demos/route/multi/multi_route_demo.jsx +277 -0
  43. package/src/components/details/details.jsx +248 -0
  44. package/src/components/details/summary_marker.jsx +141 -0
  45. package/src/components/editable_text/editable_text.jsx +96 -0
  46. package/src/components/error_boundary_context.js +9 -0
  47. package/src/components/form.jsx +144 -0
  48. package/src/components/input/button.jsx +333 -0
  49. package/src/components/input/checkbox_list.jsx +294 -0
  50. package/src/components/input/field.jsx +61 -0
  51. package/src/components/input/field_css.js +118 -0
  52. package/src/components/input/input.jsx +15 -0
  53. package/src/components/input/input_checkbox.jsx +370 -0
  54. package/src/components/input/input_radio.jsx +299 -0
  55. package/src/components/input/input_textual.jsx +338 -0
  56. package/src/components/input/radio_list.jsx +283 -0
  57. package/src/components/input/select.jsx +273 -0
  58. package/src/components/input/use_form_event.js +20 -0
  59. package/src/components/input/use_on_change.js +12 -0
  60. package/src/components/link/link.jsx +291 -0
  61. package/src/components/loader/loader_background.jsx +324 -0
  62. package/src/components/loader/loading_spinner.jsx +68 -0
  63. package/src/components/loader/network_speed.js +83 -0
  64. package/src/components/loader/rectangle_loading.jsx +225 -0
  65. package/src/components/route.jsx +15 -0
  66. package/src/components/selection/selection.js +5 -0
  67. package/src/components/selection/selection_context.jsx +262 -0
  68. package/src/components/shortcut/os.js +9 -0
  69. package/src/components/shortcut/shortcut_context.jsx +390 -0
  70. package/src/components/use_action_events.js +37 -0
  71. package/src/components/use_auto_focus.js +43 -0
  72. package/src/components/use_debounce_true.js +31 -0
  73. package/src/components/use_focus_group.js +19 -0
  74. package/src/components/use_initial_value.js +104 -0
  75. package/src/components/use_is_visited.js +19 -0
  76. package/src/components/use_ref_array.js +38 -0
  77. package/src/components/use_signal_sync.js +50 -0
  78. package/src/components/use_state_array.js +40 -0
  79. package/src/docs/actions.md +228 -0
  80. package/src/docs/demos/resource/action_status.jsx +42 -0
  81. package/src/docs/demos/resource/demo.md +1 -0
  82. package/src/docs/demos/resource/resource_demo_0.html +84 -0
  83. package/src/docs/demos/resource/resource_demo_10_post_gc.html +364 -0
  84. package/src/docs/demos/resource/resource_demo_11_describe_many.html +362 -0
  85. package/src/docs/demos/resource/resource_demo_2.html +173 -0
  86. package/src/docs/demos/resource/resource_demo_3_filtered_users.html +415 -0
  87. package/src/docs/demos/resource/resource_demo_4_details.html +284 -0
  88. package/src/docs/demos/resource/resource_demo_5_renderer_lazy.html +115 -0
  89. package/src/docs/demos/resource/resource_demo_6_gc.html +217 -0
  90. package/src/docs/demos/resource/resource_demo_7_child_gc.html +240 -0
  91. package/src/docs/demos/resource/resource_demo_8_proxy_gc.html +319 -0
  92. package/src/docs/demos/resource/resource_demo_9_describe_one.html +472 -0
  93. package/src/docs/demos/resource/tata.jsx +3 -0
  94. package/src/docs/demos/resource/toto.jsx +3 -0
  95. package/src/docs/demos/user_nav/user_nav.html +12 -0
  96. package/src/docs/demos/user_nav/user_nav.jsx +330 -0
  97. package/src/docs/resource_dependencies.md +103 -0
  98. package/src/docs/resource_with_params.md +80 -0
  99. package/src/notes.md +13 -0
  100. package/src/route/route.js +518 -0
  101. package/src/route/route.test.html +228 -0
  102. package/src/store/array_signal_store.js +537 -0
  103. package/src/store/local_storage_signal.js +17 -0
  104. package/src/store/resource_graph.js +1303 -0
  105. package/src/store/tests/resource_graph_autoreload_demo.html +12 -0
  106. package/src/store/tests/resource_graph_autoreload_demo.jsx +964 -0
  107. package/src/store/tests/resource_graph_dependencies.test.js +95 -0
  108. package/src/store/value_in_local_storage.js +187 -0
  109. package/src/symbol_object_signal.js +1 -0
  110. package/src/use_action_data.js +10 -0
  111. package/src/use_action_status.js +47 -0
  112. package/src/utils/add_many_event_listeners.js +15 -0
  113. package/src/utils/array_add_remove.js +61 -0
  114. package/src/utils/array_signal.js +15 -0
  115. package/src/utils/compare_two_js_values.js +172 -0
  116. package/src/utils/execute_with_cleanup.js +21 -0
  117. package/src/utils/get_caller_info.js +85 -0
  118. package/src/utils/iterable_weak_set.js +62 -0
  119. package/src/utils/js_value_weak_map.js +162 -0
  120. package/src/utils/js_value_weak_map_demo.html +690 -0
  121. package/src/utils/merge_two_js_values.js +53 -0
  122. package/src/utils/stringify_for_display.js +150 -0
  123. package/src/utils/weak_effect.js +48 -0
package/index.js ADDED
@@ -0,0 +1,51 @@
1
+ // actions
2
+ export { createAction, rerunActions, updateActions } from "./src/actions.js";
3
+ export {
4
+ ShortcutProvider,
5
+ useKeyboardShortcuts,
6
+ } from "./src/components/shortcut/shortcut_context.jsx";
7
+ export { useActionData } from "./src/use_action_data.js";
8
+ export { useActionStatus } from "./src/use_action_status.js";
9
+
10
+ // state management (store)
11
+ export { resource } from "./src/store/resource_graph.js";
12
+ export { valueInLocalStorage } from "./src/store/value_in_local_storage.js";
13
+
14
+ // integration with browser (and routing)
15
+ export {
16
+ actionIntegratedVia,
17
+ goBack,
18
+ goForward,
19
+ goTo,
20
+ reload,
21
+ stopLoad,
22
+ useNavState,
23
+ } from "./src/browser_integration/browser_integration.js";
24
+ export { useDocumentState } from "./src/browser_integration/document_state_signal.js";
25
+ export { useDocumentUrl } from "./src/browser_integration/document_url_signal.js";
26
+ export { defineRoutes, setBaseUrl, useRouteStatus } from "./src/route/route.js";
27
+
28
+ // UI
29
+ export { ActionRenderer } from "./src/components/action_renderer.jsx";
30
+ export { Details } from "./src/components/details/details.jsx";
31
+ export { SummaryMarker } from "./src/components/details/summary_marker.jsx";
32
+ export {
33
+ EditableText,
34
+ useEditableController,
35
+ } from "./src/components/editable_text/editable_text.jsx";
36
+ export { ErrorBoundaryContext } from "./src/components/error_boundary_context.js";
37
+ export { Form } from "./src/components/form.jsx";
38
+ export { Button } from "./src/components/input/button.jsx";
39
+ export { CheckboxList } from "./src/components/input/checkbox_list.jsx";
40
+ export { Field } from "./src/components/input/field.jsx";
41
+ export { Input } from "./src/components/input/input.jsx";
42
+ export { RadioList } from "./src/components/input/radio_list.jsx";
43
+ export { Select } from "./src/components/input/select.jsx";
44
+ export { Link } from "./src/components/link/link.jsx";
45
+ export { Route } from "./src/components/route.jsx";
46
+ export { SelectionProvider } from "./src/components/selection/selection.js";
47
+ export { useSignalSync } from "./src/components/use_signal_sync.js";
48
+
49
+ // for debbugging testing purposes
50
+ export { enableDebugActions } from "./src/actions.js";
51
+ export { enableDebugOnDocumentLoading } from "./src/browser_integration/document_loading_signal.js";
package/package.json ADDED
@@ -0,0 +1,38 @@
1
+ {
2
+ "name": "@jsenv/navi",
3
+ "version": "0.0.1",
4
+ "description": "A navigation library for JS environments",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "https://github.com/jsenv/core",
8
+ "directory": "packages/frontend/navi"
9
+ },
10
+ "license": "MIT",
11
+ "author": {
12
+ "name": "dmail",
13
+ "email": "dmaillard06@gmail.com"
14
+ },
15
+ "sideEffects": false,
16
+ "type": "module",
17
+ "exports": {
18
+ ".": "./index.js",
19
+ "./*": "./*"
20
+ },
21
+ "files": [
22
+ "/index.js",
23
+ "/src/"
24
+ ],
25
+ "dependencies": {
26
+ "@jsenv/dom": "0.0.1",
27
+ "@jsenv/humanize": "1.6.0"
28
+ },
29
+ "devDependencies": {
30
+ "@jsenv/assert": "4.5.3",
31
+ "@jsenv/validation": "0.0.1",
32
+ "@preact/signals": "2.2.0",
33
+ "preact": "10.26.9"
34
+ },
35
+ "publishConfig": {
36
+ "access": "public"
37
+ }
38
+ }
@@ -0,0 +1,11 @@
1
+ const actionPrivatePropertiesWeakMap = new WeakMap();
2
+ export const getActionPrivateProperties = (action) => {
3
+ const actionPrivateProperties = actionPrivatePropertiesWeakMap.get(action);
4
+ if (!actionPrivateProperties) {
5
+ throw new Error(`Cannot find action private properties for "${action}"`);
6
+ }
7
+ return actionPrivateProperties;
8
+ };
9
+ export const setActionPrivateProperties = (action, properties) => {
10
+ actionPrivatePropertiesWeakMap.set(action, properties);
11
+ };
@@ -0,0 +1,353 @@
1
+ <!doctype html>
2
+ <html>
3
+ <head>
4
+ <title>Action Proxy Test</title>
5
+ <meta charset="utf-8" />
6
+ <link rel="icon" href="data:," />
7
+ <style>
8
+ body {
9
+ font-family: Arial, sans-serif;
10
+ max-width: 1000px;
11
+ margin: 0 auto;
12
+ padding: 10px;
13
+ }
14
+ .section {
15
+ border: 1px solid #ccc;
16
+ margin: 10px 0;
17
+ padding: 15px;
18
+ border-radius: 5px;
19
+ }
20
+ .section h3 {
21
+ margin-top: 0;
22
+ }
23
+ .controls {
24
+ margin: 10px 0;
25
+ }
26
+ .controls button {
27
+ margin: 5px;
28
+ padding: 8px 16px;
29
+ border: 1px solid #007acc;
30
+ background: #007acc;
31
+ color: white;
32
+ border-radius: 3px;
33
+ cursor: pointer;
34
+ }
35
+ .controls button:hover {
36
+ background: #005999;
37
+ }
38
+ .controls button:disabled {
39
+ background: #ccc;
40
+ border-color: #ccc;
41
+ cursor: not-allowed;
42
+ }
43
+ .status {
44
+ background: #f5f5f5;
45
+ padding: 10px;
46
+ margin: 10px 0;
47
+ border-radius: 3px;
48
+ font-family: monospace;
49
+ }
50
+ .input-group {
51
+ margin: 10px 0;
52
+ }
53
+ .input-group label {
54
+ display: inline-block;
55
+ width: 100px;
56
+ font-weight: bold;
57
+ }
58
+ .input-group input {
59
+ padding: 5px;
60
+ border: 1px solid #ccc;
61
+ border-radius: 3px;
62
+ }
63
+ .execution-count {
64
+ font-size: 18px;
65
+ font-weight: bold;
66
+ color: #007acc;
67
+ }
68
+ .log {
69
+ background: #f9f9f9;
70
+ border: 1px solid #ddd;
71
+ padding: 10px;
72
+ height: 200px;
73
+ overflow-y: auto;
74
+ font-family: monospace;
75
+ font-size: 12px;
76
+ }
77
+ </style>
78
+ </head>
79
+
80
+ <body>
81
+ <h1>Action Proxy with Signal Parameters Test</h1>
82
+
83
+ <div class="section">
84
+ <h3>Signal Control</h3>
85
+ <div class="input-group">
86
+ <label>User ID:</label>
87
+ <input type="number" id="userIdInput" value="123" />
88
+ <button onclick="updateSignal()">Update Signal</button>
89
+ <button onclick="replaceParams()">Replace Params</button>
90
+ </div>
91
+ <div class="status">
92
+ Current Signal Value: <span id="signalValue">123</span>
93
+ </div>
94
+ </div>
95
+
96
+ <div style="display: flex; gap: 10px; flex: 1; width: 100%">
97
+ <div class="section" style="flex: 1">
98
+ <h3>Action Proxy Status</h3>
99
+ <div class="status">
100
+ <div>Name: <span id="proxyName">-</span></div>
101
+ <div>Params: <span id="proxyParams">-</span></div>
102
+ <div>Loading State: <span id="proxyLoadingState">-</span></div>
103
+ <div>Load Requested: <span id="proxyLoadRequested">-</span></div>
104
+ <div>Data: <span id="proxyData">-</span></div>
105
+ <div>Error: <span id="proxyError">-</span></div>
106
+ </div>
107
+ </div>
108
+
109
+ <div class="section" style="flex: 1">
110
+ <h3>All Actions & Proxy Target</h3>
111
+ <div class="status">
112
+ <div id="actionsList" style="margin-top: 5px; font-size: 11px">-</div>
113
+ </div>
114
+ </div>
115
+ </div>
116
+
117
+ <div class="section">
118
+ <h3>Execution Counter</h3>
119
+ <div class="status">
120
+ <div class="execution-count">
121
+ Action executed: <span id="executionCount">0</span> times
122
+ </div>
123
+ </div>
124
+ </div>
125
+
126
+ <div class="section">
127
+ <h3>Controls</h3>
128
+ <div class="controls">
129
+ <button onclick="loadAction()">Load</button>
130
+ <button onclick="reloadAction()">Reload</button>
131
+ <button onclick="unloadAction()">Unload</button>
132
+ <button onclick="abortAction()">Abort</button>
133
+ <button onclick="preloadAction()">Preload</button>
134
+ </div>
135
+ </div>
136
+
137
+ <div class="section">
138
+ <h3>Log</h3>
139
+ <div id="log" class="log"></div>
140
+ <button onclick="clearLog()">Clear Log</button>
141
+ </div>
142
+
143
+ <script type="module">
144
+ import { signal, effect } from "@preact/signals";
145
+ import { createAction } from "./actions.js";
146
+ import { getActionPrivateProperties } from "./action_private_properties.js";
147
+
148
+ // Global state
149
+ let executionCount = 0;
150
+ let userAction;
151
+ let userActionProxy;
152
+ let userIdSignal;
153
+
154
+ // DOM elements
155
+ const elements = {
156
+ signalValue: document.getElementById("signalValue"),
157
+ proxyName: document.getElementById("proxyName"),
158
+ proxyParams: document.getElementById("proxyParams"),
159
+ proxyLoadingState: document.getElementById("proxyLoadingState"),
160
+ proxyLoadRequested: document.getElementById("proxyLoadRequested"),
161
+ proxyData: document.getElementById("proxyData"),
162
+ proxyError: document.getElementById("proxyError"),
163
+ actionsList: document.getElementById("actionsList"),
164
+ executionCount: document.getElementById("executionCount"),
165
+ userIdInput: document.getElementById("userIdInput"),
166
+ log: document.getElementById("log"),
167
+ };
168
+
169
+ // Logging utility
170
+ function log(message) {
171
+ const timestamp = new Date().toLocaleTimeString();
172
+ const logElement = elements.log;
173
+ logElement.innerHTML += `[${timestamp}] ${message}\n`;
174
+ logElement.scrollTop = logElement.scrollHeight;
175
+ }
176
+
177
+ // Create the action that simulates fetching user data
178
+ userAction = createAction(
179
+ async (userId, { signal, reason, isPreload }) => {
180
+ executionCount++;
181
+ elements.executionCount.textContent = executionCount;
182
+
183
+ log(
184
+ `🚀 Action executing with userId: ${userId} (reason: ${reason}, isPreload: ${isPreload})`,
185
+ );
186
+
187
+ // Simulate async work
188
+ await new Promise((resolve) => setTimeout(resolve, 1000));
189
+
190
+ // Check if aborted
191
+ if (signal.aborted) {
192
+ log(`❌ Action aborted: ${signal.reason}`);
193
+ throw new Error(`Aborted: ${signal.reason}`);
194
+ }
195
+
196
+ const userData = {
197
+ id: userId,
198
+ loadedAt: new Date().toISOString(),
199
+ };
200
+
201
+ log(`✅ Action completed with data: ${JSON.stringify(userData)}`);
202
+ return userData;
203
+ },
204
+ {
205
+ name: "fetchUser",
206
+ },
207
+ );
208
+
209
+ // Create signal for user ID
210
+ userIdSignal = signal("123");
211
+
212
+ // Create proxy action bound to the signal
213
+ userActionProxy = userAction.bindParams(userIdSignal);
214
+
215
+ // Update UI functions
216
+ function updateSignalDisplay() {
217
+ elements.signalValue.textContent = userIdSignal.value;
218
+ }
219
+
220
+ function updateProxyDisplay() {
221
+ // Watch proxy properties through private properties signals
222
+ const {
223
+ paramsSignal,
224
+ loadingStateSignal,
225
+ loadRequestedSignal,
226
+ dataSignal,
227
+ errorSignal,
228
+ } = getActionPrivateProperties(userActionProxy);
229
+
230
+ elements.proxyName.textContent = userActionProxy.name;
231
+ elements.proxyParams.textContent = JSON.stringify(paramsSignal.value);
232
+ elements.proxyLoadingState.textContent = loadingStateSignal.value.id;
233
+ elements.proxyLoadRequested.textContent = loadRequestedSignal.value;
234
+ elements.proxyData.textContent = JSON.stringify(dataSignal.value);
235
+ elements.proxyError.textContent = errorSignal.value || "null";
236
+ }
237
+
238
+ function updateActionsDisplay() {
239
+ // Get all actions (exclude proxies)
240
+ const allActions = userAction.matchAllSelfOrDescendant(() => true);
241
+
242
+ // Get the current action the proxy is pointing at
243
+ const currentProxyTarget =
244
+ getActionPrivateProperties(userActionProxy).currentAction;
245
+
246
+ // Create actions list
247
+ if (allActions.length === 0) {
248
+ elements.actionsList.innerHTML = "No actions exist";
249
+ } else {
250
+ const actionsHtml = allActions
251
+ .map((action) => {
252
+ const isCurrentTarget = action === currentProxyTarget;
253
+ const actionData = action.data
254
+ ? JSON.stringify(action.data).substring(0, 50) +
255
+ (JSON.stringify(action.data).length > 50 ? "..." : "")
256
+ : "null";
257
+ const style = isCurrentTarget
258
+ ? "background: #ffffcc; font-weight: bold;"
259
+ : "";
260
+ const indicator = isCurrentTarget ? "👉 " : " ";
261
+
262
+ return `<div style="${style}; padding: 2px; margin: 1px 0; border-radius: 2px;">
263
+ ${indicator}<strong>${action.name}</strong> | Data: ${actionData} | State: ${action.loadingState.id}
264
+ </div>`;
265
+ })
266
+ .join("");
267
+
268
+ elements.actionsList.innerHTML = actionsHtml;
269
+ }
270
+ }
271
+
272
+ // Set up reactive updates
273
+ effect(() => {
274
+ // Watch the signal value
275
+ updateSignalDisplay();
276
+
277
+ updateProxyDisplay();
278
+
279
+ // Watch underlying action properties
280
+ const currentAction = userActionProxy.matchAllSelfOrDescendant(
281
+ () => true,
282
+ { includeProxies: false },
283
+ )[0];
284
+ if (currentAction) {
285
+ const actionPrivateProps = getActionPrivateProperties(currentAction);
286
+ // Subscribe to action state changes by accessing signal values
287
+ /* eslint-disable-next-line no-unused-expressions */
288
+ actionPrivateProps.loadingStateSignal.value;
289
+ /* eslint-disable-next-line no-unused-expressions */
290
+ actionPrivateProps.loadRequestedSignal.value;
291
+ /* eslint-disable-next-line no-unused-expressions */
292
+ actionPrivateProps.dataSignal.value;
293
+ /* eslint-disable-next-line no-unused-expressions */
294
+ actionPrivateProps.errorSignal.value;
295
+ }
296
+ updateActionsDisplay();
297
+ });
298
+
299
+ // Global functions for buttons
300
+ window.updateSignal = function () {
301
+ const newValue = elements.userIdInput.valueAsNumber;
302
+ log(`📡 Updating signal from "${userIdSignal.value}" to "${newValue}"`);
303
+ userIdSignal.value = newValue;
304
+ };
305
+
306
+ window.replaceParams = function () {
307
+ const newValue = elements.userIdInput.valueAsNumber;
308
+ log(
309
+ `🔄 Replacing params from "${JSON.stringify(userActionProxy.params)}" to "{userId: ${newValue}}"`,
310
+ );
311
+ userActionProxy.replaceParams(newValue);
312
+ };
313
+
314
+ window.loadAction = function () {
315
+ log(`🔄 Loading action proxy`);
316
+ userActionProxy.load({ reason: "Manual load button clicked" });
317
+ };
318
+
319
+ window.reloadAction = function () {
320
+ log(`🔄 Reloading action proxy`);
321
+ userActionProxy.reload({ reason: "Manual reload button clicked" });
322
+ };
323
+
324
+ window.unloadAction = function () {
325
+ log(`🛑 Unloading action proxy`);
326
+ userActionProxy.unload();
327
+ };
328
+
329
+ window.abortAction = function () {
330
+ log(`⚠️ Aborting action proxy`);
331
+ userActionProxy.abort("Manual abort button clicked");
332
+ };
333
+
334
+ window.preloadAction = function () {
335
+ log(`⏳ Preloading action proxy`);
336
+ userActionProxy.preload({ reason: "Manual preload button clicked" });
337
+ };
338
+
339
+ window.clearLog = function () {
340
+ elements.log.innerHTML = "";
341
+ };
342
+
343
+ // Initial update
344
+ updateSignalDisplay();
345
+ updateProxyDisplay();
346
+ updateActionsDisplay();
347
+
348
+ log(
349
+ `🎯 Test setup complete. Action proxy bound to signal with initial value: ${userIdSignal.value}`,
350
+ );
351
+ </script>
352
+ </body>
353
+ </html>
@@ -0,0 +1,5 @@
1
+ export const IDLE = { id: "idle" };
2
+ export const RUNNING = { id: "running" };
3
+ export const ABORTED = { id: "aborted" };
4
+ export const FAILED = { id: "failed" };
5
+ export const COMPLETED = { id: "completed" };