@jsenv/navi 0.10.2 → 0.11.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 (207) hide show
  1. package/dist/jsenv_navi.js +13838 -23291
  2. package/dist/jsenv_navi.js.map +1281 -0
  3. package/package.json +6 -8
  4. package/index.js +0 -122
  5. package/src/action_private_properties.js +0 -11
  6. package/src/action_proxy_test.html +0 -353
  7. package/src/action_run_states.js +0 -5
  8. package/src/actions.js +0 -1401
  9. package/src/browser_integration/browser_integration.js +0 -216
  10. package/src/browser_integration/document_back_and_forward.js +0 -17
  11. package/src/browser_integration/document_loading_signal.js +0 -100
  12. package/src/browser_integration/document_state_signal.js +0 -9
  13. package/src/browser_integration/document_url_signal.js +0 -9
  14. package/src/browser_integration/use_is_visited.js +0 -19
  15. package/src/browser_integration/via_history.js +0 -232
  16. package/src/browser_integration/via_navigation.js +0 -168
  17. package/src/components/action_execution/form_context.js +0 -5
  18. package/src/components/action_execution/render_actionable_component.jsx +0 -29
  19. package/src/components/action_execution/use_action.js +0 -99
  20. package/src/components/action_execution/use_execute_action.js +0 -193
  21. package/src/components/action_execution/use_run_on_mount.js +0 -9
  22. package/src/components/action_renderer.jsx +0 -125
  23. package/src/components/callout/callout.js +0 -990
  24. package/src/components/callout/callout_demo.html +0 -201
  25. package/src/components/callout/test_dynamic_positioning.html +0 -161
  26. package/src/components/callout/test_html_document_iframe.html +0 -182
  27. package/src/components/demos/0_button_demo.html +0 -707
  28. package/src/components/demos/10_column_reordering_debug.html +0 -277
  29. package/src/components/demos/11_table_selection_debug.html +0 -432
  30. package/src/components/demos/1_checkbox_demo.html +0 -754
  31. package/src/components/demos/2_input_textual_demo.html +0 -286
  32. package/src/components/demos/3_radio_demo.html +0 -874
  33. package/src/components/demos/4_select_demo.html +0 -100
  34. package/src/components/demos/5_list_scrollable_demo.html +0 -153
  35. package/src/components/demos/6_tablist_demo.html +0 -77
  36. package/src/components/demos/7_table_selection_demo.html +0 -176
  37. package/src/components/demos/8_table_fixed_headers_demo.html +0 -584
  38. package/src/components/demos/9_table_column_drag_demo.html +0 -325
  39. package/src/components/demos/action/0_button_demo.html +0 -204
  40. package/src/components/demos/action/10_shortcuts_demo.html +0 -189
  41. package/src/components/demos/action/11_nested_shortcuts_demo.xhtml +0 -401
  42. package/src/components/demos/action/1_input_text_demo.html +0 -876
  43. package/src/components/demos/action/2_form_multiple.html +0 -303
  44. package/src/components/demos/action/3_details_demo.html +0 -203
  45. package/src/components/demos/action/4_input_checkbox_demo.html +0 -731
  46. package/src/components/demos/action/5_input_checkbox_state_demo.html +0 -270
  47. package/src/components/demos/action/6_checkbox_list_demo.html +0 -341
  48. package/src/components/demos/action/7_radio_list_demo.html +0 -357
  49. package/src/components/demos/action/8_editable_demo.html +0 -431
  50. package/src/components/demos/action/9_link_demo.html +0 -194
  51. package/src/components/demos/demo.md +0 -0
  52. package/src/components/demos/route/basic/basic.html +0 -14
  53. package/src/components/demos/route/basic/basic_route_demo.jsx +0 -224
  54. package/src/components/demos/route/multi/multi.html +0 -14
  55. package/src/components/demos/route/multi/multi_route_demo.jsx +0 -277
  56. package/src/components/demos/ui_transition/0_action_renderer_ui_transition_demo.html +0 -695
  57. package/src/components/demos/ui_transition/1_nested_ui_transition_demo.html +0 -429
  58. package/src/components/demos/ui_transition/2_height_transition_test.html +0 -295
  59. package/src/components/details/details.jsx +0 -245
  60. package/src/components/details/summary_marker.jsx +0 -141
  61. package/src/components/edition/editable.jsx +0 -186
  62. package/src/components/error_boundary_context.js +0 -9
  63. package/src/components/field/README.md +0 -247
  64. package/src/components/field/button.jsx +0 -429
  65. package/src/components/field/checkbox_list.jsx +0 -185
  66. package/src/components/field/collect_form_element_values.js +0 -82
  67. package/src/components/field/custom_field.js +0 -106
  68. package/src/components/field/form.jsx +0 -209
  69. package/src/components/field/input.jsx +0 -16
  70. package/src/components/field/input_checkbox.jsx +0 -434
  71. package/src/components/field/input_radio.jsx +0 -432
  72. package/src/components/field/input_textual.jsx +0 -389
  73. package/src/components/field/label.jsx +0 -46
  74. package/src/components/field/radio_list.jsx +0 -183
  75. package/src/components/field/select.jsx +0 -256
  76. package/src/components/field/use_action_events.js +0 -132
  77. package/src/components/field/use_form_events.js +0 -59
  78. package/src/components/field/use_ui_state_controller.js +0 -506
  79. package/src/components/item_tracker/README.md +0 -461
  80. package/src/components/item_tracker/use_isolated_item_tracker.jsx +0 -209
  81. package/src/components/item_tracker/use_isolated_item_tracker_demo.html +0 -148
  82. package/src/components/item_tracker/use_isolated_item_tracker_demo.jsx +0 -460
  83. package/src/components/item_tracker/use_item_tracker.jsx +0 -143
  84. package/src/components/item_tracker/use_item_tracker_demo.html +0 -207
  85. package/src/components/item_tracker/use_item_tracker_demo.jsx +0 -216
  86. package/src/components/keyboard_shortcuts/active_keyboard_shortcuts.jsx +0 -87
  87. package/src/components/keyboard_shortcuts/aria_key_shortcuts.js +0 -61
  88. package/src/components/keyboard_shortcuts/keyboard_key_meta.js +0 -17
  89. package/src/components/keyboard_shortcuts/keyboard_shortcuts.js +0 -371
  90. package/src/components/keyboard_shortcuts/os.js +0 -9
  91. package/src/components/layout/demos/demo_flex.html +0 -638
  92. package/src/components/layout/demos/demo_layout_style_buttons.html +0 -351
  93. package/src/components/layout/demos/demo_layout_style_input.html +0 -226
  94. package/src/components/layout/demos/demo_layout_style_text.html +0 -514
  95. package/src/components/layout/flex.jsx +0 -109
  96. package/src/components/layout/layout_context.jsx +0 -3
  97. package/src/components/layout/spacing.jsx +0 -20
  98. package/src/components/layout/use_layout_style.js +0 -249
  99. package/src/components/link/link.jsx +0 -267
  100. package/src/components/link/link_with_icon.jsx +0 -52
  101. package/src/components/loader/loader_background.jsx +0 -372
  102. package/src/components/loader/loading_spinner.jsx +0 -68
  103. package/src/components/loader/network_speed.js +0 -83
  104. package/src/components/loader/rectangle_loading.jsx +0 -244
  105. package/src/components/props_composition/demos/demo_with_props_style.html +0 -81
  106. package/src/components/props_composition/with_props_class_name.js +0 -37
  107. package/src/components/props_composition/with_props_style.js +0 -26
  108. package/src/components/route.jsx +0 -19
  109. package/src/components/selection/selection.jsx +0 -1583
  110. package/src/components/svg/font_sized_svg.jsx +0 -59
  111. package/src/components/svg/icon_and_text.jsx +0 -21
  112. package/src/components/svg/svg_mask_overlay.jsx +0 -105
  113. package/src/components/table/drag/table_drag.jsx +0 -506
  114. package/src/components/table/resize/table_resize.jsx +0 -650
  115. package/src/components/table/resize/table_size.js +0 -43
  116. package/src/components/table/selection/table_selection.js +0 -106
  117. package/src/components/table/selection/table_selection.jsx +0 -203
  118. package/src/components/table/sticky/sticky_group.js +0 -354
  119. package/src/components/table/sticky/table_sticky.js +0 -25
  120. package/src/components/table/sticky/table_sticky.jsx +0 -501
  121. package/src/components/table/table.jsx +0 -721
  122. package/src/components/table/table_css.js +0 -211
  123. package/src/components/table/table_ui.jsx +0 -49
  124. package/src/components/table/use_cells_and_columns.js +0 -90
  125. package/src/components/table/use_object_array_to_cells.js +0 -46
  126. package/src/components/table/z_indexes.js +0 -23
  127. package/src/components/tablist/tablist.jsx +0 -99
  128. package/src/components/text/demos/demo_text_and_icon.html +0 -421
  129. package/src/components/text/overflow.jsx +0 -15
  130. package/src/components/text/text.jsx +0 -83
  131. package/src/components/text/text_and_count.jsx +0 -28
  132. package/src/components/ui_transition.jsx +0 -128
  133. package/src/components/use_auto_focus.js +0 -94
  134. package/src/components/use_batch_during_render.js +0 -33
  135. package/src/components/use_debounce_true.js +0 -31
  136. package/src/components/use_dependencies_diff.js +0 -35
  137. package/src/components/use_focus_group.js +0 -20
  138. package/src/components/use_initial_value.js +0 -78
  139. package/src/components/use_is_visited.js +0 -19
  140. package/src/components/use_ref_array.js +0 -38
  141. package/src/components/use_signal_sync.js +0 -50
  142. package/src/components/use_stable_callback.js +0 -68
  143. package/src/components/use_state_array.js +0 -47
  144. package/src/docs/actions.md +0 -250
  145. package/src/docs/demos/resource/action_status.jsx +0 -42
  146. package/src/docs/demos/resource/demo.md +0 -1
  147. package/src/docs/demos/resource/resource_demo_0.html +0 -84
  148. package/src/docs/demos/resource/resource_demo_10_post_gc.html +0 -364
  149. package/src/docs/demos/resource/resource_demo_11_describe_many.html +0 -362
  150. package/src/docs/demos/resource/resource_demo_2.html +0 -173
  151. package/src/docs/demos/resource/resource_demo_3_filtered_users.html +0 -415
  152. package/src/docs/demos/resource/resource_demo_4_details.html +0 -284
  153. package/src/docs/demos/resource/resource_demo_5_renderer_lazy.html +0 -115
  154. package/src/docs/demos/resource/resource_demo_6_gc.html +0 -217
  155. package/src/docs/demos/resource/resource_demo_7_child_gc.html +0 -240
  156. package/src/docs/demos/resource/resource_demo_8_proxy_gc.html +0 -319
  157. package/src/docs/demos/resource/resource_demo_9_describe_one.html +0 -472
  158. package/src/docs/demos/resource/tata.jsx +0 -3
  159. package/src/docs/demos/resource/toto.jsx +0 -3
  160. package/src/docs/demos/user_nav/user_nav.html +0 -12
  161. package/src/docs/demos/user_nav/user_nav.jsx +0 -330
  162. package/src/docs/resource_dependencies.md +0 -103
  163. package/src/docs/resource_with_params.md +0 -80
  164. package/src/navi_css_vars.js +0 -14
  165. package/src/notes.md +0 -34
  166. package/src/route/route.js +0 -596
  167. package/src/route/route.xtest.html +0 -228
  168. package/src/store/array_signal_store.js +0 -537
  169. package/src/store/local_storage_signal.js +0 -17
  170. package/src/store/resource_graph.js +0 -1304
  171. package/src/store/tests/resource_graph_autoreload_demo.html +0 -12
  172. package/src/store/tests/resource_graph_autoreload_demo.jsx +0 -964
  173. package/src/store/tests/resource_graph_dependencies.test_manual.js +0 -95
  174. package/src/store/value_in_local_storage.js +0 -187
  175. package/src/symbol_object_signal.js +0 -1
  176. package/src/use_action_data.js +0 -10
  177. package/src/use_action_status.js +0 -47
  178. package/src/utils/add_many_event_listeners.js +0 -15
  179. package/src/utils/array_add_remove.js +0 -61
  180. package/src/utils/array_signal.js +0 -15
  181. package/src/utils/compare_two_js_values.js +0 -172
  182. package/src/utils/execute_with_cleanup.js +0 -21
  183. package/src/utils/get_caller_info.js +0 -85
  184. package/src/utils/is_signal.js +0 -20
  185. package/src/utils/js_value_weak_map.js +0 -162
  186. package/src/utils/js_value_weak_map_demo.html +0 -690
  187. package/src/utils/merge_two_js_values.js +0 -53
  188. package/src/utils/stringify_for_display.js +0 -131
  189. package/src/utils/weak_effect.js +0 -48
  190. package/src/validation/constraints/confirm_constraint.js +0 -14
  191. package/src/validation/constraints/create_unique_value_constraint.js +0 -27
  192. package/src/validation/constraints/native_constraints.js +0 -338
  193. package/src/validation/constraints/readonly_constraint.js +0 -41
  194. package/src/validation/constraints/same_as_constraint.js +0 -42
  195. package/src/validation/constraints/single_space_constraint.js +0 -13
  196. package/src/validation/custom_constraint_validation.js +0 -793
  197. package/src/validation/custom_message.js +0 -18
  198. package/src/validation/demos/browser_style.png +0 -0
  199. package/src/validation/demos/demo_same_as_constraint.html +0 -259
  200. package/src/validation/demos/form_validation_demo.html +0 -142
  201. package/src/validation/demos/form_validation_demo_preact.html +0 -87
  202. package/src/validation/demos/form_validation_native_popover_demo.html +0 -168
  203. package/src/validation/demos/form_validation_vs_native_demo.html +0 -172
  204. package/src/validation/hooks/use_constraints.js +0 -23
  205. package/src/validation/hooks/use_custom_validation_ref.js +0 -73
  206. package/src/validation/hooks/use_validation_message.js +0 -19
  207. package/src/validation/input_change_effect.js +0 -106
@@ -1,95 +0,0 @@
1
- // Example test demonstrating the dependency system
2
- import { resource } from "../resource_graph.js";
3
-
4
- // Create test resources
5
- const role = resource("role", {
6
- GET_MANY: () =>
7
- Promise.resolve([
8
- { id: 1, name: "admin" },
9
- { id: 2, name: "user" },
10
- ]),
11
- POST: (data) => Promise.resolve({ id: Date.now(), ...data }),
12
- DELETE: (id) => Promise.resolve(id),
13
- });
14
-
15
- const database = resource("database", {
16
- GET_MANY: () =>
17
- Promise.resolve([
18
- { id: 1, name: "main_db" },
19
- { id: 2, name: "test_db" },
20
- ]),
21
- POST: (data) => Promise.resolve({ id: Date.now(), ...data }),
22
- DELETE: (id) => Promise.resolve(id),
23
- });
24
-
25
- const tables = resource("tables", {
26
- GET_MANY: () =>
27
- Promise.resolve([
28
- { id: 1, name: "users", database_id: 1 },
29
- { id: 2, name: "roles", database_id: 1 },
30
- ]),
31
- POST: (data) => Promise.resolve({ id: Date.now(), ...data }),
32
- DELETE: (id) => Promise.resolve(id),
33
- });
34
-
35
- // Create parameterized resource with dependencies
36
- // This will autoreload when any of the dependency resources are modified
37
- const ROLE_WITH_OWNERSHIP = role.withParams(
38
- { owners: true },
39
- {
40
- dependencies: [role, database, tables],
41
- },
42
- );
43
-
44
- // Demonstrate the functionality
45
- console.log("🚀 Dependency system demo");
46
- console.log(
47
- `✅ Created ROLE_WITH_OWNERSHIP with ${ROLE_WITH_OWNERSHIP.dependencies.length} dependencies`,
48
- );
49
- console.log(
50
- `📋 Dependencies: ${ROLE_WITH_OWNERSHIP.dependencies.map((d) => d.name).join(", ")}`,
51
- );
52
-
53
- // Test the autoreload mechanism
54
- async function testAutorerun() {
55
- console.log("\n🧪 Testing autorerun mechanism...");
56
-
57
- try {
58
- // Load the parameterized resource
59
- const ownershipData = await ROLE_WITH_OWNERSHIP.GET_MANY.run();
60
- console.log(
61
- "✅ ROLE_WITH_OWNERSHIP.GET_MANY.run() executed:",
62
- ownershipData.length,
63
- "items",
64
- );
65
-
66
- // Trigger dependency changes that should cause autorerun
67
- console.log("\n📝 Triggering dependency changes...");
68
-
69
- await tables.POST.run({ name: "new_table", database_id: 1 });
70
- console.log(
71
- "✅ tables.POST.run() - should trigger ROLE_WITH_OWNERSHIP autorerun",
72
- );
73
-
74
- await database.POST.run({ name: "new_database" });
75
- console.log(
76
- "✅ database.POST.run() - should trigger ROLE_WITH_OWNERSHIP autorerun",
77
- );
78
-
79
- await role.POST.run({ name: "new_role" });
80
- console.log(
81
- "✅ role.POST.run() - should trigger ROLE_WITH_OWNERSHIP autorerun",
82
- );
83
-
84
- console.log("\n✅ Dependency system test completed successfully!");
85
- console.log(
86
- "💡 In a real application, these would automatically rerun ROLE_WITH_OWNERSHIP.GET_MANY",
87
- );
88
- } catch (error) {
89
- console.error("❌ Test failed:", error);
90
- }
91
- }
92
-
93
- testAutorerun();
94
-
95
- export { database, role, ROLE_WITH_OWNERSHIP, tables };
@@ -1,187 +0,0 @@
1
- export const valueInLocalStorage = (key, options = {}) => {
2
- const { type = "string" } = options;
3
- const converter = typeConverters[type];
4
- if (converter === undefined) {
5
- console.warn(
6
- `Invalid type "${type}" for "${key}" in local storage, expected one of ${Object.keys(
7
- typeConverters,
8
- ).join(", ")}`,
9
- );
10
- }
11
- const getValidityMessage = (
12
- valueToCheck,
13
- valueInLocalStorage = valueToCheck,
14
- ) => {
15
- if (!converter) {
16
- return "";
17
- }
18
- if (!converter.checkValidity) {
19
- return "";
20
- }
21
- const checkValidityResult = converter.checkValidity(valueToCheck);
22
- if (checkValidityResult === false) {
23
- return `${valueInLocalStorage}`;
24
- }
25
- if (!checkValidityResult) {
26
- return "";
27
- }
28
- return `${checkValidityResult}, got "${valueInLocalStorage}"`;
29
- };
30
-
31
- const get = () => {
32
- let valueInLocalStorage = window.localStorage.getItem(key);
33
- if (valueInLocalStorage === null) {
34
- return Object.hasOwn(options, "default") ? options.default : undefined;
35
- }
36
- if (converter && converter.decode) {
37
- const valueDecoded = converter.decode(valueInLocalStorage);
38
- const validityMessage = getValidityMessage(
39
- valueDecoded,
40
- valueInLocalStorage,
41
- );
42
- if (validityMessage) {
43
- console.warn(
44
- `The value found in localStorage "${key}" is invalid: ${validityMessage}`,
45
- );
46
- return undefined;
47
- }
48
- return valueDecoded;
49
- }
50
- const validityMessage = getValidityMessage(valueInLocalStorage);
51
- if (validityMessage) {
52
- console.warn(
53
- `The value found in localStorage "${key}" is invalid: ${validityMessage}`,
54
- );
55
- return undefined;
56
- }
57
- return valueInLocalStorage;
58
- };
59
- const set = (value) => {
60
- if (value === undefined) {
61
- window.localStorage.removeItem(key);
62
- return;
63
- }
64
- const validityMessage = getValidityMessage(value);
65
- if (validityMessage) {
66
- console.warn(
67
- `The value to set in localStorage "${key}" is invalid: ${validityMessage}`,
68
- );
69
- }
70
- if (converter && converter.encode) {
71
- const valueEncoded = converter.encode(value);
72
- window.localStorage.setItem(key, valueEncoded);
73
- return;
74
- }
75
- window.localStorage.setItem(key, value);
76
- };
77
- const remove = () => {
78
- window.localStorage.removeItem(key);
79
- };
80
-
81
- return [get, set, remove];
82
- };
83
-
84
- const typeConverters = {
85
- boolean: {
86
- checkValidity: (value) => {
87
- if (typeof value !== "boolean") {
88
- return `must be a boolean`;
89
- }
90
- return "";
91
- },
92
- decode: (value) => {
93
- return value === "true";
94
- },
95
- },
96
- string: {
97
- checkValidity: (value) => {
98
- if (typeof value !== "string") {
99
- return `must be a string`;
100
- }
101
- return "";
102
- },
103
- },
104
- number: {
105
- decode: (value) => {
106
- const valueParsed = parseFloat(value);
107
- return valueParsed;
108
- },
109
- checkValidity: (value) => {
110
- if (typeof value !== "number") {
111
- return `must be a number`;
112
- }
113
- if (!Number.isFinite(value)) {
114
- return `must be finite`;
115
- }
116
- return "";
117
- },
118
- },
119
- positive_number: {
120
- decode: (value) => {
121
- const valueParsed = parseFloat(value);
122
- return valueParsed;
123
- },
124
- checkValidity: (value) => {
125
- if (typeof value !== "number") {
126
- return `must be a number`;
127
- }
128
- if (value < 0) {
129
- return `must be positive`;
130
- }
131
- return "";
132
- },
133
- },
134
- positive_integer: {
135
- decode: (value) => {
136
- const valueParsed = parseInt(value, 10);
137
- return valueParsed;
138
- },
139
- checkValidity: (value) => {
140
- if (typeof value !== "number") {
141
- return `must be a number`;
142
- }
143
- if (!Number.isInteger(value)) {
144
- return `must be an integer`;
145
- }
146
- if (value < 0) {
147
- return `must be positive`;
148
- }
149
- return "";
150
- },
151
- },
152
- percentage: {
153
- checkValidity: (value) => {
154
- if (typeof value !== "string") {
155
- return `must be a percentage`;
156
- }
157
- if (!value.endsWith("%")) {
158
- return `must end with %`;
159
- }
160
- const percentageString = value.slice(0, -1);
161
- const percentageFloat = parseFloat(percentageString);
162
- if (typeof percentageFloat !== "number") {
163
- return `must be a percentage`;
164
- }
165
- if (percentageFloat < 0 || percentageFloat > 100) {
166
- return `must be between 0 and 100`;
167
- }
168
- return "";
169
- },
170
- },
171
- object: {
172
- decode: (value) => {
173
- const valueParsed = JSON.parse(value);
174
- return valueParsed;
175
- },
176
- encode: (value) => {
177
- const valueStringified = JSON.stringify(value);
178
- return valueStringified;
179
- },
180
- checkValidity: (value) => {
181
- if (value === null || typeof value !== "object") {
182
- return `must be an object`;
183
- }
184
- return "";
185
- },
186
- },
187
- };
@@ -1 +0,0 @@
1
- export const SYMBOL_OBJECT_SIGNAL = Symbol.for("navi_object_signal");
@@ -1,10 +0,0 @@
1
- import { getActionPrivateProperties } from "./action_private_properties.js";
2
-
3
- export const useActionData = (action) => {
4
- if (!action) {
5
- return undefined;
6
- }
7
- const { computedDataSignal } = getActionPrivateProperties(action);
8
- const data = computedDataSignal.value;
9
- return data;
10
- };
@@ -1,47 +0,0 @@
1
- import { getActionPrivateProperties } from "./action_private_properties.js";
2
- import { ABORTED, COMPLETED, IDLE, RUNNING } from "./action_run_states.js";
3
-
4
- export const useActionStatus = (action) => {
5
- if (!action) {
6
- return {
7
- params: undefined,
8
- runningState: IDLE,
9
- isPrerun: false,
10
- idle: true,
11
- loading: false,
12
- aborted: false,
13
- error: null,
14
- completed: false,
15
- data: undefined,
16
- };
17
- }
18
- const {
19
- paramsSignal,
20
- runningStateSignal,
21
- isPrerunSignal,
22
- errorSignal,
23
- computedDataSignal,
24
- } = getActionPrivateProperties(action);
25
-
26
- const params = paramsSignal.value;
27
- const isPrerun = isPrerunSignal.value;
28
- const runningState = runningStateSignal.value;
29
- const idle = runningState === IDLE;
30
- const aborted = runningState === ABORTED;
31
- const error = errorSignal.value;
32
- const loading = runningState === RUNNING;
33
- const completed = runningState === COMPLETED;
34
- const data = computedDataSignal.value;
35
-
36
- return {
37
- params,
38
- runningState,
39
- isPrerun,
40
- idle,
41
- loading,
42
- aborted,
43
- error,
44
- completed,
45
- data,
46
- };
47
- };
@@ -1,15 +0,0 @@
1
- export const addManyEventListeners = (element, events) => {
2
- const cleanupCallbackSet = new Set();
3
- for (const event of Object.keys(events)) {
4
- const callback = events[event];
5
- element.addEventListener(event, callback);
6
- cleanupCallbackSet.add(() => {
7
- element.removeEventListener(event, callback);
8
- });
9
- }
10
- return () => {
11
- for (const cleanupCallback of cleanupCallbackSet) {
12
- cleanupCallback();
13
- }
14
- };
15
- };
@@ -1,61 +0,0 @@
1
- export const addIntoArray = (array, ...valuesToAdd) => {
2
- if (valuesToAdd.length === 1) {
3
- const [valueToAdd] = valuesToAdd;
4
- const arrayWithThisValue = [];
5
- for (const value of array) {
6
- if (value === valueToAdd) {
7
- return array;
8
- }
9
- arrayWithThisValue.push(value);
10
- }
11
- arrayWithThisValue.push(valueToAdd);
12
- return arrayWithThisValue;
13
- }
14
-
15
- const existingValueSet = new Set();
16
- const arrayWithTheseValues = [];
17
- for (const existingValue of array) {
18
- arrayWithTheseValues.push(existingValue);
19
- existingValueSet.add(existingValue);
20
- }
21
- let hasNewValues = false;
22
- for (const valueToAdd of valuesToAdd) {
23
- if (existingValueSet.has(valueToAdd)) {
24
- continue;
25
- }
26
- arrayWithTheseValues.push(valueToAdd);
27
- hasNewValues = true;
28
- }
29
- return hasNewValues ? arrayWithTheseValues : array;
30
- };
31
-
32
- export const removeFromArray = (array, ...valuesToRemove) => {
33
- if (valuesToRemove.length === 1) {
34
- const [valueToRemove] = valuesToRemove;
35
- const arrayWithoutThisValue = [];
36
- let found = false;
37
- for (const value of array) {
38
- if (value === valueToRemove) {
39
- found = true;
40
- continue;
41
- }
42
- arrayWithoutThisValue.push(value);
43
- }
44
- if (!found) {
45
- return array;
46
- }
47
- return arrayWithoutThisValue;
48
- }
49
-
50
- const valuesToRemoveSet = new Set(valuesToRemove);
51
- const arrayWithoutTheseValues = [];
52
- let hasRemovedValues = false;
53
- for (const value of array) {
54
- if (valuesToRemoveSet.has(value)) {
55
- hasRemovedValues = true;
56
- continue;
57
- }
58
- arrayWithoutTheseValues.push(value);
59
- }
60
- return hasRemovedValues ? arrayWithoutTheseValues : array;
61
- };
@@ -1,15 +0,0 @@
1
- import { signal } from "@preact/signals";
2
- import { addIntoArray, removeFromArray } from "./array_add_remove.js";
3
-
4
- export const arraySignal = (initialValue = []) => {
5
- const theSignal = signal(initialValue);
6
-
7
- const add = (...args) => {
8
- theSignal.value = addIntoArray(theSignal.peek(), ...args);
9
- };
10
- const remove = (...args) => {
11
- theSignal.value = removeFromArray(theSignal.peek(), ...args);
12
- };
13
-
14
- return [theSignal, add, remove];
15
- };
@@ -1,172 +0,0 @@
1
- /**
2
- * Deep equality comparison for JavaScript values with cycle detection and identity optimization.
3
- *
4
- * This function performs a comprehensive deep comparison between two JavaScript values,
5
- * handling all primitive types, objects, arrays, and edge cases that standard equality
6
- * operators miss.
7
- *
8
- * Key features:
9
- * - **Deep comparison**: Recursively compares nested objects and arrays
10
- * - **Cycle detection**: Prevents infinite loops with circular references
11
- * - **Identity optimization**: Uses SYMBOL_IDENTITY for fast comparison of objects with same identity
12
- * - **Edge case handling**: Properly handles NaN, null, undefined, 0, false comparisons
13
- * - **Type safety**: Ensures both values have same type before deep comparison
14
- *
15
- * Performance optimizations:
16
- * - Early exit for reference equality (a === b)
17
- * - Identity symbol check for objects (avoids deep comparison when possible)
18
- * - Efficient array length check before element-by-element comparison
19
- *
20
- * **SYMBOL_IDENTITY explained**:
21
- * This symbol allows recognizing objects as "conceptually the same" even when they are
22
- * different object instances. When two objects share the same SYMBOL_IDENTITY value,
23
- * they are considered equal without performing deep comparison.
24
- *
25
- * This is particularly useful for:
26
- * - Copied objects that should be treated as the same entity
27
- * - Objects reconstructed from serialization that represent the same data
28
- * - Parameters passed through spread operator: `{ ...originalParams, newProp: value }`
29
- * - Memoization scenarios where object content identity matters more than reference identity
30
- *
31
- * Use cases:
32
- * - Memoization cache key comparison ({ id: 1 } should equal { id: 1 })
33
- * - React/Preact dependency comparison for effects and memos
34
- * - State change detection in signals and stores
35
- * - Action parameter comparison for avoiding duplicate requests
36
- * - Object recognition across serialization/deserialization boundaries
37
- *
38
- * Examples:
39
- * ```js
40
- * // Standard deep comparison
41
- * compareTwoJsValues({ id: 1 }, { id: 1 }) // true (slow - deep comparison)
42
- *
43
- * // NaN edge case handling
44
- * compareTwoJsValues(NaN, NaN) // true (unlike === which gives false)
45
- *
46
- * // Identity optimization - objects are different instances but same identity
47
- * const originalParams = { userId: 123, filters: ['active'] };
48
- * const copiedParams = { ...originalParams, newFlag: true };
49
- *
50
- * // Without SYMBOL_IDENTITY: slow deep comparison every time
51
- * compareTwoJsValues(originalParams, copiedParams) // false (different content)
52
- *
53
- * // With SYMBOL_IDENTITY: fast path recognition
54
- * const sharedIdentity = Symbol('params-identity');
55
- * originalParams[SYMBOL_IDENTITY] = sharedIdentity;
56
- * copiedParams[SYMBOL_IDENTITY] = sharedIdentity;
57
- *
58
- * compareTwoJsValues(originalParams, copiedParams) // true (fast - identity match)
59
- * // ↑ This returns true immediately without comparing all properties
60
- *
61
- * // Real-world scenario: action memoization
62
- * const params1 = { userId: 123 };
63
- * const action1 = createAction(params1);
64
- *
65
- * const params2 = { ...params1, extra: 'data' }; // Different object reference
66
- * params2[SYMBOL_IDENTITY] = params1[SYMBOL_IDENTITY]; // Same conceptual identity
67
- *
68
- * const action2 = createAction(params2);
69
- * // action1 === action2 because params are recognized as conceptually identical
70
- * ```
71
- *
72
- * @param {any} a - First value to compare
73
- * @param {any} b - Second value to compare
74
- * @param {Set} seenSet - Internal cycle detection set (automatically managed)
75
- * @returns {boolean} true if values are deeply equal, false otherwise
76
- */
77
-
78
- /**
79
- * Symbol used to mark objects with a conceptual identity that transcends reference equality.
80
- *
81
- * When two different object instances share the same SYMBOL_IDENTITY value, they are
82
- * considered equal by compareTwoJsValues without performing expensive deep comparison.
83
- *
84
- * This enables recognition of "the same logical object" even when:
85
- * - The object has been copied via spread operator: `{ ...obj, newProp }`
86
- * - The object has been reconstructed from serialization
87
- * - The object is a different instance but represents the same conceptual entity
88
- *
89
- * Use Symbol.for() to ensure the same symbol across different modules/contexts.
90
- */
91
- export const SYMBOL_IDENTITY = Symbol.for("navi_object_identity");
92
-
93
- export const compareTwoJsValues = (a, b, seenSet = new Set()) => {
94
- if (a === b) {
95
- return true;
96
- }
97
- const aIsIsTruthy = Boolean(a);
98
- const bIsTruthy = Boolean(b);
99
- if (aIsIsTruthy && !bIsTruthy) {
100
- return false;
101
- }
102
- if (!aIsIsTruthy && !bIsTruthy) {
103
- // null, undefined, 0, false, NaN
104
- if (isNaN(a) && isNaN(b)) {
105
- return true;
106
- }
107
- return a === b;
108
- }
109
- const aType = typeof a;
110
- const bType = typeof b;
111
- if (aType !== bType) {
112
- return false;
113
- }
114
- const aIsPrimitive =
115
- a === null || (aType !== "object" && aType !== "function");
116
- const bIsPrimitive =
117
- b === null || (bType !== "object" && bType !== "function");
118
- if (aIsPrimitive !== bIsPrimitive) {
119
- return false;
120
- }
121
- if (aIsPrimitive && bIsPrimitive) {
122
- return a === b;
123
- }
124
- if (seenSet.has(a)) {
125
- return false;
126
- }
127
- if (seenSet.has(b)) {
128
- return false;
129
- }
130
- seenSet.add(a);
131
- seenSet.add(b);
132
- const aIsArray = Array.isArray(a);
133
- const bIsArray = Array.isArray(b);
134
- if (aIsArray !== bIsArray) {
135
- return false;
136
- }
137
- if (aIsArray) {
138
- // compare arrays
139
- if (a.length !== b.length) {
140
- return false;
141
- }
142
- let i = 0;
143
- while (i < a.length) {
144
- const aValue = a[i];
145
- const bValue = b[i];
146
- if (!compareTwoJsValues(aValue, bValue, seenSet)) {
147
- return false;
148
- }
149
- i++;
150
- }
151
- return true;
152
- }
153
- // compare objects
154
- const aIdentity = a[SYMBOL_IDENTITY];
155
- const bIdentity = b[SYMBOL_IDENTITY];
156
- if (aIdentity === bIdentity && SYMBOL_IDENTITY in a && SYMBOL_IDENTITY in b) {
157
- return true;
158
- }
159
- const aKeys = Object.keys(a);
160
- const bKeys = Object.keys(b);
161
- if (aKeys.length !== bKeys.length) {
162
- return false;
163
- }
164
- for (const key of aKeys) {
165
- const aValue = a[key];
166
- const bValue = b[key];
167
- if (!compareTwoJsValues(aValue, bValue, seenSet)) {
168
- return false;
169
- }
170
- }
171
- return true;
172
- };
@@ -1,21 +0,0 @@
1
- export const executeWithCleanup = (fn, cleanup) => {
2
- let isThenable;
3
- try {
4
- const result = fn();
5
- isThenable = result && typeof result.then === "function";
6
- if (isThenable) {
7
- return (async () => {
8
- try {
9
- return await result;
10
- } finally {
11
- cleanup();
12
- }
13
- })();
14
- }
15
- return result;
16
- } finally {
17
- if (!isThenable) {
18
- cleanup();
19
- }
20
- }
21
- };