@jsenv/navi 0.10.2 → 0.11.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/dist/jsenv_navi.js +13838 -23291
- package/dist/jsenv_navi.js.map +1281 -0
- package/package.json +5 -7
- package/index.js +0 -122
- package/src/action_private_properties.js +0 -11
- package/src/action_proxy_test.html +0 -353
- package/src/action_run_states.js +0 -5
- package/src/actions.js +0 -1401
- package/src/browser_integration/browser_integration.js +0 -216
- package/src/browser_integration/document_back_and_forward.js +0 -17
- package/src/browser_integration/document_loading_signal.js +0 -100
- package/src/browser_integration/document_state_signal.js +0 -9
- package/src/browser_integration/document_url_signal.js +0 -9
- package/src/browser_integration/use_is_visited.js +0 -19
- package/src/browser_integration/via_history.js +0 -232
- package/src/browser_integration/via_navigation.js +0 -168
- package/src/components/action_execution/form_context.js +0 -5
- package/src/components/action_execution/render_actionable_component.jsx +0 -29
- package/src/components/action_execution/use_action.js +0 -99
- package/src/components/action_execution/use_execute_action.js +0 -193
- package/src/components/action_execution/use_run_on_mount.js +0 -9
- package/src/components/action_renderer.jsx +0 -125
- package/src/components/callout/callout.js +0 -990
- package/src/components/callout/callout_demo.html +0 -201
- package/src/components/callout/test_dynamic_positioning.html +0 -161
- package/src/components/callout/test_html_document_iframe.html +0 -182
- package/src/components/demos/0_button_demo.html +0 -707
- package/src/components/demos/10_column_reordering_debug.html +0 -277
- package/src/components/demos/11_table_selection_debug.html +0 -432
- package/src/components/demos/1_checkbox_demo.html +0 -754
- package/src/components/demos/2_input_textual_demo.html +0 -286
- package/src/components/demos/3_radio_demo.html +0 -874
- package/src/components/demos/4_select_demo.html +0 -100
- package/src/components/demos/5_list_scrollable_demo.html +0 -153
- package/src/components/demos/6_tablist_demo.html +0 -77
- package/src/components/demos/7_table_selection_demo.html +0 -176
- package/src/components/demos/8_table_fixed_headers_demo.html +0 -584
- package/src/components/demos/9_table_column_drag_demo.html +0 -325
- package/src/components/demos/action/0_button_demo.html +0 -204
- package/src/components/demos/action/10_shortcuts_demo.html +0 -189
- package/src/components/demos/action/11_nested_shortcuts_demo.xhtml +0 -401
- package/src/components/demos/action/1_input_text_demo.html +0 -876
- package/src/components/demos/action/2_form_multiple.html +0 -303
- package/src/components/demos/action/3_details_demo.html +0 -203
- package/src/components/demos/action/4_input_checkbox_demo.html +0 -731
- package/src/components/demos/action/5_input_checkbox_state_demo.html +0 -270
- package/src/components/demos/action/6_checkbox_list_demo.html +0 -341
- package/src/components/demos/action/7_radio_list_demo.html +0 -357
- package/src/components/demos/action/8_editable_demo.html +0 -431
- package/src/components/demos/action/9_link_demo.html +0 -194
- package/src/components/demos/demo.md +0 -0
- package/src/components/demos/route/basic/basic.html +0 -14
- package/src/components/demos/route/basic/basic_route_demo.jsx +0 -224
- package/src/components/demos/route/multi/multi.html +0 -14
- package/src/components/demos/route/multi/multi_route_demo.jsx +0 -277
- package/src/components/demos/ui_transition/0_action_renderer_ui_transition_demo.html +0 -695
- package/src/components/demos/ui_transition/1_nested_ui_transition_demo.html +0 -429
- package/src/components/demos/ui_transition/2_height_transition_test.html +0 -295
- package/src/components/details/details.jsx +0 -245
- package/src/components/details/summary_marker.jsx +0 -141
- package/src/components/edition/editable.jsx +0 -186
- package/src/components/error_boundary_context.js +0 -9
- package/src/components/field/README.md +0 -247
- package/src/components/field/button.jsx +0 -429
- package/src/components/field/checkbox_list.jsx +0 -185
- package/src/components/field/collect_form_element_values.js +0 -82
- package/src/components/field/custom_field.js +0 -106
- package/src/components/field/form.jsx +0 -209
- package/src/components/field/input.jsx +0 -16
- package/src/components/field/input_checkbox.jsx +0 -434
- package/src/components/field/input_radio.jsx +0 -432
- package/src/components/field/input_textual.jsx +0 -389
- package/src/components/field/label.jsx +0 -46
- package/src/components/field/radio_list.jsx +0 -183
- package/src/components/field/select.jsx +0 -256
- package/src/components/field/use_action_events.js +0 -132
- package/src/components/field/use_form_events.js +0 -59
- package/src/components/field/use_ui_state_controller.js +0 -506
- package/src/components/item_tracker/README.md +0 -461
- package/src/components/item_tracker/use_isolated_item_tracker.jsx +0 -209
- package/src/components/item_tracker/use_isolated_item_tracker_demo.html +0 -148
- package/src/components/item_tracker/use_isolated_item_tracker_demo.jsx +0 -460
- package/src/components/item_tracker/use_item_tracker.jsx +0 -143
- package/src/components/item_tracker/use_item_tracker_demo.html +0 -207
- package/src/components/item_tracker/use_item_tracker_demo.jsx +0 -216
- package/src/components/keyboard_shortcuts/active_keyboard_shortcuts.jsx +0 -87
- package/src/components/keyboard_shortcuts/aria_key_shortcuts.js +0 -61
- package/src/components/keyboard_shortcuts/keyboard_key_meta.js +0 -17
- package/src/components/keyboard_shortcuts/keyboard_shortcuts.js +0 -371
- package/src/components/keyboard_shortcuts/os.js +0 -9
- package/src/components/layout/demos/demo_flex.html +0 -638
- package/src/components/layout/demos/demo_layout_style_buttons.html +0 -351
- package/src/components/layout/demos/demo_layout_style_input.html +0 -226
- package/src/components/layout/demos/demo_layout_style_text.html +0 -514
- package/src/components/layout/flex.jsx +0 -109
- package/src/components/layout/layout_context.jsx +0 -3
- package/src/components/layout/spacing.jsx +0 -20
- package/src/components/layout/use_layout_style.js +0 -249
- package/src/components/link/link.jsx +0 -267
- package/src/components/link/link_with_icon.jsx +0 -52
- package/src/components/loader/loader_background.jsx +0 -372
- package/src/components/loader/loading_spinner.jsx +0 -68
- package/src/components/loader/network_speed.js +0 -83
- package/src/components/loader/rectangle_loading.jsx +0 -244
- package/src/components/props_composition/demos/demo_with_props_style.html +0 -81
- package/src/components/props_composition/with_props_class_name.js +0 -37
- package/src/components/props_composition/with_props_style.js +0 -26
- package/src/components/route.jsx +0 -19
- package/src/components/selection/selection.jsx +0 -1583
- package/src/components/svg/font_sized_svg.jsx +0 -59
- package/src/components/svg/icon_and_text.jsx +0 -21
- package/src/components/svg/svg_mask_overlay.jsx +0 -105
- package/src/components/table/drag/table_drag.jsx +0 -506
- package/src/components/table/resize/table_resize.jsx +0 -650
- package/src/components/table/resize/table_size.js +0 -43
- package/src/components/table/selection/table_selection.js +0 -106
- package/src/components/table/selection/table_selection.jsx +0 -203
- package/src/components/table/sticky/sticky_group.js +0 -354
- package/src/components/table/sticky/table_sticky.js +0 -25
- package/src/components/table/sticky/table_sticky.jsx +0 -501
- package/src/components/table/table.jsx +0 -721
- package/src/components/table/table_css.js +0 -211
- package/src/components/table/table_ui.jsx +0 -49
- package/src/components/table/use_cells_and_columns.js +0 -90
- package/src/components/table/use_object_array_to_cells.js +0 -46
- package/src/components/table/z_indexes.js +0 -23
- package/src/components/tablist/tablist.jsx +0 -99
- package/src/components/text/demos/demo_text_and_icon.html +0 -421
- package/src/components/text/overflow.jsx +0 -15
- package/src/components/text/text.jsx +0 -83
- package/src/components/text/text_and_count.jsx +0 -28
- package/src/components/ui_transition.jsx +0 -128
- package/src/components/use_auto_focus.js +0 -94
- package/src/components/use_batch_during_render.js +0 -33
- package/src/components/use_debounce_true.js +0 -31
- package/src/components/use_dependencies_diff.js +0 -35
- package/src/components/use_focus_group.js +0 -20
- package/src/components/use_initial_value.js +0 -78
- package/src/components/use_is_visited.js +0 -19
- package/src/components/use_ref_array.js +0 -38
- package/src/components/use_signal_sync.js +0 -50
- package/src/components/use_stable_callback.js +0 -68
- package/src/components/use_state_array.js +0 -47
- package/src/docs/actions.md +0 -250
- package/src/docs/demos/resource/action_status.jsx +0 -42
- package/src/docs/demos/resource/demo.md +0 -1
- package/src/docs/demos/resource/resource_demo_0.html +0 -84
- package/src/docs/demos/resource/resource_demo_10_post_gc.html +0 -364
- package/src/docs/demos/resource/resource_demo_11_describe_many.html +0 -362
- package/src/docs/demos/resource/resource_demo_2.html +0 -173
- package/src/docs/demos/resource/resource_demo_3_filtered_users.html +0 -415
- package/src/docs/demos/resource/resource_demo_4_details.html +0 -284
- package/src/docs/demos/resource/resource_demo_5_renderer_lazy.html +0 -115
- package/src/docs/demos/resource/resource_demo_6_gc.html +0 -217
- package/src/docs/demos/resource/resource_demo_7_child_gc.html +0 -240
- package/src/docs/demos/resource/resource_demo_8_proxy_gc.html +0 -319
- package/src/docs/demos/resource/resource_demo_9_describe_one.html +0 -472
- package/src/docs/demos/resource/tata.jsx +0 -3
- package/src/docs/demos/resource/toto.jsx +0 -3
- package/src/docs/demos/user_nav/user_nav.html +0 -12
- package/src/docs/demos/user_nav/user_nav.jsx +0 -330
- package/src/docs/resource_dependencies.md +0 -103
- package/src/docs/resource_with_params.md +0 -80
- package/src/navi_css_vars.js +0 -14
- package/src/notes.md +0 -34
- package/src/route/route.js +0 -596
- package/src/route/route.xtest.html +0 -228
- package/src/store/array_signal_store.js +0 -537
- package/src/store/local_storage_signal.js +0 -17
- package/src/store/resource_graph.js +0 -1304
- package/src/store/tests/resource_graph_autoreload_demo.html +0 -12
- package/src/store/tests/resource_graph_autoreload_demo.jsx +0 -964
- package/src/store/tests/resource_graph_dependencies.test_manual.js +0 -95
- package/src/store/value_in_local_storage.js +0 -187
- package/src/symbol_object_signal.js +0 -1
- package/src/use_action_data.js +0 -10
- package/src/use_action_status.js +0 -47
- package/src/utils/add_many_event_listeners.js +0 -15
- package/src/utils/array_add_remove.js +0 -61
- package/src/utils/array_signal.js +0 -15
- package/src/utils/compare_two_js_values.js +0 -172
- package/src/utils/execute_with_cleanup.js +0 -21
- package/src/utils/get_caller_info.js +0 -85
- package/src/utils/is_signal.js +0 -20
- package/src/utils/js_value_weak_map.js +0 -162
- package/src/utils/js_value_weak_map_demo.html +0 -690
- package/src/utils/merge_two_js_values.js +0 -53
- package/src/utils/stringify_for_display.js +0 -131
- package/src/utils/weak_effect.js +0 -48
- package/src/validation/constraints/confirm_constraint.js +0 -14
- package/src/validation/constraints/create_unique_value_constraint.js +0 -27
- package/src/validation/constraints/native_constraints.js +0 -338
- package/src/validation/constraints/readonly_constraint.js +0 -41
- package/src/validation/constraints/same_as_constraint.js +0 -42
- package/src/validation/constraints/single_space_constraint.js +0 -13
- package/src/validation/custom_constraint_validation.js +0 -793
- package/src/validation/custom_message.js +0 -18
- package/src/validation/demos/browser_style.png +0 -0
- package/src/validation/demos/demo_same_as_constraint.html +0 -259
- package/src/validation/demos/form_validation_demo.html +0 -142
- package/src/validation/demos/form_validation_demo_preact.html +0 -87
- package/src/validation/demos/form_validation_native_popover_demo.html +0 -168
- package/src/validation/demos/form_validation_vs_native_demo.html +0 -172
- package/src/validation/hooks/use_constraints.js +0 -23
- package/src/validation/hooks/use_custom_validation_ref.js +0 -73
- package/src/validation/hooks/use_validation_message.js +0 -19
- package/src/validation/input_change_effect.js +0 -106
|
@@ -1,537 +0,0 @@
|
|
|
1
|
-
import { computed, effect, signal } from "@preact/signals";
|
|
2
|
-
|
|
3
|
-
export const primitiveCanBeId = (value) => {
|
|
4
|
-
const type = typeof value;
|
|
5
|
-
if (type === "string" || type === "number" || type === "symbol") {
|
|
6
|
-
return true;
|
|
7
|
-
}
|
|
8
|
-
return false;
|
|
9
|
-
};
|
|
10
|
-
|
|
11
|
-
export const arraySignalStore = (
|
|
12
|
-
initialArray = [],
|
|
13
|
-
idKey = "id",
|
|
14
|
-
{
|
|
15
|
-
mutableIdKeys = [],
|
|
16
|
-
name,
|
|
17
|
-
createItem = (props) => {
|
|
18
|
-
return { ...props };
|
|
19
|
-
},
|
|
20
|
-
},
|
|
21
|
-
) => {
|
|
22
|
-
const store = {
|
|
23
|
-
name,
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
const createItemFromProps = (props) => {
|
|
27
|
-
if (props === null || typeof props !== "object") {
|
|
28
|
-
return props;
|
|
29
|
-
}
|
|
30
|
-
const item = createItem(props);
|
|
31
|
-
return item;
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
const arraySignal = signal(initialArray);
|
|
35
|
-
const derivedSignal = computed(() => {
|
|
36
|
-
const array = arraySignal.value;
|
|
37
|
-
const idSet = new Set(); // will be used to detect id changes (deletion, addition)
|
|
38
|
-
const idMap = new Map(); // used to speep up finding item by id
|
|
39
|
-
for (const item of array) {
|
|
40
|
-
const id = item[idKey];
|
|
41
|
-
idSet.add(id);
|
|
42
|
-
idMap.set(id, item);
|
|
43
|
-
}
|
|
44
|
-
return [idSet, idMap];
|
|
45
|
-
});
|
|
46
|
-
const idSetSignal = computed(() => derivedSignal.value[0]);
|
|
47
|
-
const idMapSignal = computed(() => derivedSignal.value[1]);
|
|
48
|
-
const previousIdSetSignal = signal(new Set(idSetSignal.peek()));
|
|
49
|
-
const idChangeCallbackSet = new Set();
|
|
50
|
-
effect(() => {
|
|
51
|
-
const idSet = idSetSignal.value;
|
|
52
|
-
const previousIdSet = previousIdSetSignal.peek();
|
|
53
|
-
const setCopy = new Set();
|
|
54
|
-
let modified = false;
|
|
55
|
-
for (const id of idSet) {
|
|
56
|
-
if (!previousIdSet.has(id)) {
|
|
57
|
-
modified = true;
|
|
58
|
-
}
|
|
59
|
-
setCopy.add(id);
|
|
60
|
-
}
|
|
61
|
-
if (modified) {
|
|
62
|
-
previousIdSetSignal.value = setCopy;
|
|
63
|
-
for (const idChangeCallback of idChangeCallbackSet) {
|
|
64
|
-
idChangeCallback(idSet, previousIdSet);
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
const propertiesObserverSet = new Set();
|
|
70
|
-
const observeProperties = (itemSignal, callback) => {
|
|
71
|
-
const observer = { itemSignal, callback };
|
|
72
|
-
propertiesObserverSet.add(observer);
|
|
73
|
-
|
|
74
|
-
// Return cleanup function
|
|
75
|
-
return () => {
|
|
76
|
-
propertiesObserverSet.delete(observer);
|
|
77
|
-
};
|
|
78
|
-
};
|
|
79
|
-
|
|
80
|
-
const removalsCallbackSet = new Set();
|
|
81
|
-
const observeRemovals = (callback) => {
|
|
82
|
-
removalsCallbackSet.add(callback);
|
|
83
|
-
};
|
|
84
|
-
|
|
85
|
-
const itemMatchLifecycleSet = new Set();
|
|
86
|
-
const registerItemMatchLifecycle = (matchPredicate, { match, nomatch }) => {
|
|
87
|
-
const matchState = {
|
|
88
|
-
hasMatched: false,
|
|
89
|
-
hadMatchedBefore: false,
|
|
90
|
-
};
|
|
91
|
-
const itemMatchLifecycle = {
|
|
92
|
-
matchPredicate,
|
|
93
|
-
match,
|
|
94
|
-
nomatch,
|
|
95
|
-
matchState,
|
|
96
|
-
};
|
|
97
|
-
itemMatchLifecycleSet.add(itemMatchLifecycle);
|
|
98
|
-
};
|
|
99
|
-
|
|
100
|
-
const readIdFromItemProps = (props, array) => {
|
|
101
|
-
let id;
|
|
102
|
-
if (Object.hasOwn(props, idKey)) {
|
|
103
|
-
id = props[idKey];
|
|
104
|
-
return id;
|
|
105
|
-
}
|
|
106
|
-
if (mutableIdKeys.length === 0) {
|
|
107
|
-
return undefined;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
let mutableIdKey;
|
|
111
|
-
for (const mutableIdKeyCandidate of mutableIdKeys) {
|
|
112
|
-
if (Object.hasOwn(props, mutableIdKeyCandidate)) {
|
|
113
|
-
mutableIdKey = mutableIdKeyCandidate;
|
|
114
|
-
break;
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
if (!mutableIdKey) {
|
|
118
|
-
throw new Error(
|
|
119
|
-
`item properties must have one of the following keys:
|
|
120
|
-
${[idKey, ...mutableIdKeys].join(", ")}`,
|
|
121
|
-
);
|
|
122
|
-
}
|
|
123
|
-
const mutableIdValue = props[mutableIdKey];
|
|
124
|
-
for (const itemCandidate of array) {
|
|
125
|
-
const mutableIdCandidate = itemCandidate[mutableIdKey];
|
|
126
|
-
if (mutableIdCandidate === mutableIdValue) {
|
|
127
|
-
id = itemCandidate[idKey];
|
|
128
|
-
break;
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
if (!id) {
|
|
132
|
-
throw new Error(
|
|
133
|
-
`None of the existing item uses ${mutableIdKey}: ${mutableIdValue}, so item properties must specify the "${idKey}" key.`,
|
|
134
|
-
);
|
|
135
|
-
}
|
|
136
|
-
return id;
|
|
137
|
-
};
|
|
138
|
-
|
|
139
|
-
effect(() => {
|
|
140
|
-
const array = arraySignal.value;
|
|
141
|
-
|
|
142
|
-
for (const {
|
|
143
|
-
matchPredicate,
|
|
144
|
-
match,
|
|
145
|
-
nomatch,
|
|
146
|
-
matchState,
|
|
147
|
-
} of itemMatchLifecycleSet) {
|
|
148
|
-
let currentlyHasMatch = false;
|
|
149
|
-
|
|
150
|
-
// Check if any item currently matches
|
|
151
|
-
for (const item of array) {
|
|
152
|
-
if (matchPredicate(item)) {
|
|
153
|
-
currentlyHasMatch = true;
|
|
154
|
-
break;
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
// Handle state transitions
|
|
159
|
-
if (currentlyHasMatch && !matchState.hasMatched) {
|
|
160
|
-
// New match found
|
|
161
|
-
matchState.hasMatched = true;
|
|
162
|
-
const isRematch = matchState.hadMatchedBefore;
|
|
163
|
-
if (match) {
|
|
164
|
-
match(isRematch);
|
|
165
|
-
}
|
|
166
|
-
} else if (!currentlyHasMatch && matchState.hasMatched) {
|
|
167
|
-
// No longer has match
|
|
168
|
-
matchState.hasMatched = false;
|
|
169
|
-
matchState.hadMatchedBefore = true;
|
|
170
|
-
if (nomatch) {
|
|
171
|
-
nomatch();
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
});
|
|
176
|
-
|
|
177
|
-
const select = (...args) => {
|
|
178
|
-
const array = arraySignal.value;
|
|
179
|
-
const idMap = idMapSignal.value;
|
|
180
|
-
|
|
181
|
-
let property;
|
|
182
|
-
let value;
|
|
183
|
-
if (args.length === 1) {
|
|
184
|
-
property = idKey;
|
|
185
|
-
value = args[0];
|
|
186
|
-
if (value !== null && typeof value === "object") {
|
|
187
|
-
value = readIdFromItemProps(value, array);
|
|
188
|
-
}
|
|
189
|
-
} else if (args.length === 2) {
|
|
190
|
-
property = args[0];
|
|
191
|
-
value = args[1];
|
|
192
|
-
}
|
|
193
|
-
if (property === idKey) {
|
|
194
|
-
return idMap.get(value);
|
|
195
|
-
}
|
|
196
|
-
for (const itemCandidate of array) {
|
|
197
|
-
const valueCandidate =
|
|
198
|
-
typeof property === "function"
|
|
199
|
-
? property(itemCandidate)
|
|
200
|
-
: itemCandidate[property];
|
|
201
|
-
if (valueCandidate === value) {
|
|
202
|
-
return itemCandidate;
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
return null;
|
|
206
|
-
};
|
|
207
|
-
const selectAll = (toMatchArray) => {
|
|
208
|
-
const array = arraySignal.value;
|
|
209
|
-
const result = [];
|
|
210
|
-
const idMap = idMapSignal.value;
|
|
211
|
-
for (const toMatch of toMatchArray) {
|
|
212
|
-
const id =
|
|
213
|
-
toMatch !== null && typeof toMatch === "object"
|
|
214
|
-
? readIdFromItemProps(toMatch, array)
|
|
215
|
-
: toMatch;
|
|
216
|
-
const item = idMap.get(id);
|
|
217
|
-
if (item) {
|
|
218
|
-
result.push(item);
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
return result;
|
|
222
|
-
};
|
|
223
|
-
const upsert = (...args) => {
|
|
224
|
-
const itemMutationsMap = new Map(); // Map<itemId, propertyMutations>
|
|
225
|
-
const triggerPropertyMutations = () => {
|
|
226
|
-
if (itemMutationsMap.size === 0) {
|
|
227
|
-
return;
|
|
228
|
-
}
|
|
229
|
-
// we call at the end so that itemWithProps and arraySignal.value was set too
|
|
230
|
-
for (const observer of propertiesObserverSet) {
|
|
231
|
-
const { itemSignal, callback } = observer;
|
|
232
|
-
const watchedItem = itemSignal.peek();
|
|
233
|
-
if (!watchedItem) {
|
|
234
|
-
continue;
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
// Check if this item has mutations
|
|
238
|
-
const itemSpecificMutations = itemMutationsMap.get(watchedItem[idKey]);
|
|
239
|
-
if (itemSpecificMutations) {
|
|
240
|
-
callback(itemSpecificMutations);
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
};
|
|
244
|
-
const assign = (item, props) => {
|
|
245
|
-
const itemOwnPropertyDescriptors = Object.getOwnPropertyDescriptors(item);
|
|
246
|
-
const itemOwnKeys = Object.keys(itemOwnPropertyDescriptors);
|
|
247
|
-
const itemWithProps = Object.create(
|
|
248
|
-
Object.getPrototypeOf(item),
|
|
249
|
-
itemOwnPropertyDescriptors,
|
|
250
|
-
);
|
|
251
|
-
let hasChanges = false;
|
|
252
|
-
const propertyMutations = {};
|
|
253
|
-
|
|
254
|
-
for (const key of Object.keys(props)) {
|
|
255
|
-
const newValue = props[key];
|
|
256
|
-
if (itemOwnKeys.includes(key)) {
|
|
257
|
-
const oldValue = item[key];
|
|
258
|
-
if (newValue !== oldValue) {
|
|
259
|
-
hasChanges = true;
|
|
260
|
-
itemWithProps[key] = newValue;
|
|
261
|
-
propertyMutations[key] = {
|
|
262
|
-
oldValue,
|
|
263
|
-
newValue,
|
|
264
|
-
target: item,
|
|
265
|
-
newTarget: itemWithProps,
|
|
266
|
-
};
|
|
267
|
-
}
|
|
268
|
-
} else {
|
|
269
|
-
hasChanges = true;
|
|
270
|
-
itemWithProps[key] = newValue;
|
|
271
|
-
propertyMutations[key] = {
|
|
272
|
-
added: true,
|
|
273
|
-
newValue,
|
|
274
|
-
target: item,
|
|
275
|
-
newTarget: itemWithProps,
|
|
276
|
-
};
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
if (!hasChanges) {
|
|
281
|
-
return item;
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
// Store mutations for this specific item
|
|
285
|
-
itemMutationsMap.set(item[idKey], propertyMutations);
|
|
286
|
-
return itemWithProps;
|
|
287
|
-
};
|
|
288
|
-
|
|
289
|
-
const array = arraySignal.peek();
|
|
290
|
-
if (args.length === 1 && Array.isArray(args[0])) {
|
|
291
|
-
const propsArray = args[0];
|
|
292
|
-
if (array.length === 0) {
|
|
293
|
-
const arrayAllCreated = [];
|
|
294
|
-
for (const props of propsArray) {
|
|
295
|
-
const item = createItemFromProps(props);
|
|
296
|
-
arrayAllCreated.push(item);
|
|
297
|
-
}
|
|
298
|
-
arraySignal.value = arrayAllCreated;
|
|
299
|
-
return arrayAllCreated;
|
|
300
|
-
}
|
|
301
|
-
let hasNew = false;
|
|
302
|
-
let hasUpdate = false;
|
|
303
|
-
const arraySomeUpdated = [];
|
|
304
|
-
const arrayWithOnlyAffectedItems = [];
|
|
305
|
-
const existingEntryMap = new Map();
|
|
306
|
-
let index = 0;
|
|
307
|
-
while (index < array.length) {
|
|
308
|
-
const existingItem = array[index];
|
|
309
|
-
const id = existingItem[idKey];
|
|
310
|
-
existingEntryMap.set(id, {
|
|
311
|
-
existingItem,
|
|
312
|
-
existingItemIndex: index,
|
|
313
|
-
processed: false,
|
|
314
|
-
});
|
|
315
|
-
index++;
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
for (const props of propsArray) {
|
|
319
|
-
const id = readIdFromItemProps(props, array);
|
|
320
|
-
const existingEntry = existingEntryMap.get(id);
|
|
321
|
-
if (existingEntry) {
|
|
322
|
-
const { existingItem } = existingEntry;
|
|
323
|
-
const itemWithPropsOrItem = assign(existingItem, props);
|
|
324
|
-
if (itemWithPropsOrItem !== existingItem) {
|
|
325
|
-
hasUpdate = true;
|
|
326
|
-
}
|
|
327
|
-
arraySomeUpdated.push(itemWithPropsOrItem);
|
|
328
|
-
existingEntry.processed = true;
|
|
329
|
-
arrayWithOnlyAffectedItems.push(itemWithPropsOrItem);
|
|
330
|
-
} else {
|
|
331
|
-
hasNew = true;
|
|
332
|
-
const item = createItemFromProps(props);
|
|
333
|
-
arraySomeUpdated.push(item);
|
|
334
|
-
arrayWithOnlyAffectedItems.push(item);
|
|
335
|
-
}
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
for (const [, existingEntry] of existingEntryMap) {
|
|
339
|
-
if (!existingEntry.processed) {
|
|
340
|
-
arraySomeUpdated.push(existingEntry.existingItem);
|
|
341
|
-
}
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
if (hasNew || hasUpdate) {
|
|
345
|
-
arraySignal.value = arraySomeUpdated;
|
|
346
|
-
triggerPropertyMutations();
|
|
347
|
-
return arrayWithOnlyAffectedItems;
|
|
348
|
-
}
|
|
349
|
-
return arrayWithOnlyAffectedItems;
|
|
350
|
-
}
|
|
351
|
-
let existingItem = null;
|
|
352
|
-
let updatedItem = null;
|
|
353
|
-
const arraySomeUpdated = [];
|
|
354
|
-
let propertyToMatch;
|
|
355
|
-
let valueToMatch;
|
|
356
|
-
let props;
|
|
357
|
-
if (args.length === 1) {
|
|
358
|
-
const firstArg = args[0];
|
|
359
|
-
propertyToMatch = idKey;
|
|
360
|
-
if (!firstArg || typeof firstArg !== "object") {
|
|
361
|
-
throw new TypeError(
|
|
362
|
-
`Expected an object as first argument, got ${firstArg}`,
|
|
363
|
-
);
|
|
364
|
-
}
|
|
365
|
-
valueToMatch = readIdFromItemProps(firstArg, array);
|
|
366
|
-
props = firstArg;
|
|
367
|
-
} else if (args.length === 2) {
|
|
368
|
-
propertyToMatch = idKey;
|
|
369
|
-
valueToMatch = args[0];
|
|
370
|
-
if (typeof valueToMatch === "object") {
|
|
371
|
-
valueToMatch = valueToMatch[idKey];
|
|
372
|
-
}
|
|
373
|
-
props = args[1];
|
|
374
|
-
} else if (args.length === 3) {
|
|
375
|
-
propertyToMatch = args[0];
|
|
376
|
-
valueToMatch = args[1];
|
|
377
|
-
props = args[2];
|
|
378
|
-
}
|
|
379
|
-
for (const itemCandidate of array) {
|
|
380
|
-
const itemCandidateValue =
|
|
381
|
-
typeof propertyToMatch === "function"
|
|
382
|
-
? propertyToMatch(itemCandidate)
|
|
383
|
-
: itemCandidate[propertyToMatch];
|
|
384
|
-
if (itemCandidateValue === valueToMatch) {
|
|
385
|
-
const itemWithPropsOrItem = assign(itemCandidate, props);
|
|
386
|
-
if (itemWithPropsOrItem === itemCandidate) {
|
|
387
|
-
existingItem = itemCandidate;
|
|
388
|
-
} else {
|
|
389
|
-
updatedItem = itemWithPropsOrItem;
|
|
390
|
-
}
|
|
391
|
-
arraySomeUpdated.push(itemWithPropsOrItem);
|
|
392
|
-
} else {
|
|
393
|
-
arraySomeUpdated.push(itemCandidate);
|
|
394
|
-
}
|
|
395
|
-
}
|
|
396
|
-
if (existingItem) {
|
|
397
|
-
return existingItem;
|
|
398
|
-
}
|
|
399
|
-
if (updatedItem) {
|
|
400
|
-
arraySignal.value = arraySomeUpdated;
|
|
401
|
-
triggerPropertyMutations();
|
|
402
|
-
return updatedItem;
|
|
403
|
-
}
|
|
404
|
-
const item = createItemFromProps(props);
|
|
405
|
-
arraySomeUpdated.push(item);
|
|
406
|
-
arraySignal.value = arraySomeUpdated;
|
|
407
|
-
triggerPropertyMutations();
|
|
408
|
-
return item;
|
|
409
|
-
};
|
|
410
|
-
const drop = (...args) => {
|
|
411
|
-
const removedItemArray = [];
|
|
412
|
-
const triggerRemovedMutations = () => {
|
|
413
|
-
if (removedItemArray.length === 0) {
|
|
414
|
-
return;
|
|
415
|
-
}
|
|
416
|
-
// we call at the end so that itemWithProps and arraySignal.value was set too
|
|
417
|
-
for (const removalsCallback of removalsCallbackSet) {
|
|
418
|
-
removalsCallback(removedItemArray);
|
|
419
|
-
}
|
|
420
|
-
};
|
|
421
|
-
|
|
422
|
-
const array = arraySignal.peek();
|
|
423
|
-
if (args.length === 1 && Array.isArray(args[0])) {
|
|
424
|
-
const firstArg = args[0];
|
|
425
|
-
const arrayWithoutDroppedItems = [];
|
|
426
|
-
let hasFound = false;
|
|
427
|
-
const idToRemoveSet = new Set();
|
|
428
|
-
const idRemovedArray = [];
|
|
429
|
-
|
|
430
|
-
for (const value of firstArg) {
|
|
431
|
-
if (typeof value === "object" && value !== null) {
|
|
432
|
-
const id = readIdFromItemProps(value, array);
|
|
433
|
-
idToRemoveSet.add(id);
|
|
434
|
-
} else if (!primitiveCanBeId(value)) {
|
|
435
|
-
throw new TypeError(`id to drop must be an id, got ${value}`);
|
|
436
|
-
}
|
|
437
|
-
idToRemoveSet.add(value);
|
|
438
|
-
}
|
|
439
|
-
for (const existingItem of array) {
|
|
440
|
-
const existingItemId = existingItem[idKey];
|
|
441
|
-
if (idToRemoveSet.has(existingItemId)) {
|
|
442
|
-
hasFound = true;
|
|
443
|
-
idToRemoveSet.delete(existingItemId);
|
|
444
|
-
idRemovedArray.push(existingItemId);
|
|
445
|
-
} else {
|
|
446
|
-
arrayWithoutDroppedItems.push(existingItem);
|
|
447
|
-
}
|
|
448
|
-
}
|
|
449
|
-
if (idToRemoveSet.size > 0) {
|
|
450
|
-
console.warn(
|
|
451
|
-
`arraySignalStore.drop: Some ids were not found in the array: ${Array.from(idToRemoveSet).join(", ")}`,
|
|
452
|
-
);
|
|
453
|
-
}
|
|
454
|
-
if (hasFound) {
|
|
455
|
-
arraySignal.value = arrayWithoutDroppedItems;
|
|
456
|
-
triggerRemovedMutations();
|
|
457
|
-
return idRemovedArray;
|
|
458
|
-
}
|
|
459
|
-
return [];
|
|
460
|
-
}
|
|
461
|
-
let propertyToMatch;
|
|
462
|
-
let valueToMatch;
|
|
463
|
-
if (args.length === 1) {
|
|
464
|
-
propertyToMatch = idKey;
|
|
465
|
-
valueToMatch = args[0];
|
|
466
|
-
if (valueToMatch !== null && typeof valueToMatch === "object") {
|
|
467
|
-
valueToMatch = readIdFromItemProps(valueToMatch, array);
|
|
468
|
-
} else if (!primitiveCanBeId(valueToMatch)) {
|
|
469
|
-
throw new TypeError(`id to drop must be an id, got ${valueToMatch}`);
|
|
470
|
-
}
|
|
471
|
-
} else {
|
|
472
|
-
propertyToMatch = args[0];
|
|
473
|
-
valueToMatch = args[1];
|
|
474
|
-
}
|
|
475
|
-
const arrayWithoutItemToDrop = [];
|
|
476
|
-
let found = false;
|
|
477
|
-
let itemDropped = null;
|
|
478
|
-
for (const itemCandidate of array) {
|
|
479
|
-
const itemCandidateValue =
|
|
480
|
-
typeof propertyToMatch === "function"
|
|
481
|
-
? propertyToMatch(itemCandidate)
|
|
482
|
-
: itemCandidate[propertyToMatch];
|
|
483
|
-
if (itemCandidateValue === valueToMatch) {
|
|
484
|
-
itemDropped = itemCandidate;
|
|
485
|
-
found = true;
|
|
486
|
-
} else {
|
|
487
|
-
arrayWithoutItemToDrop.push(itemCandidate);
|
|
488
|
-
}
|
|
489
|
-
}
|
|
490
|
-
if (found) {
|
|
491
|
-
arraySignal.value = arrayWithoutItemToDrop;
|
|
492
|
-
removedItemArray.push(itemDropped);
|
|
493
|
-
triggerRemovedMutations();
|
|
494
|
-
return itemDropped[idKey];
|
|
495
|
-
}
|
|
496
|
-
return null;
|
|
497
|
-
};
|
|
498
|
-
|
|
499
|
-
const signalForMutableIdKey = (mutableIdKey, mutableIdValueSignal) => {
|
|
500
|
-
const itemIdSignal = signal(null);
|
|
501
|
-
const check = (value) => {
|
|
502
|
-
const item = select(mutableIdKey, value);
|
|
503
|
-
if (!item) {
|
|
504
|
-
return false;
|
|
505
|
-
}
|
|
506
|
-
itemIdSignal.value = item[idKey];
|
|
507
|
-
return true;
|
|
508
|
-
};
|
|
509
|
-
if (!check()) {
|
|
510
|
-
effect(function () {
|
|
511
|
-
const mutableIdValue = mutableIdValueSignal.value;
|
|
512
|
-
if (check(mutableIdValue)) {
|
|
513
|
-
this.dispose();
|
|
514
|
-
}
|
|
515
|
-
});
|
|
516
|
-
}
|
|
517
|
-
|
|
518
|
-
return computed(() => {
|
|
519
|
-
return select(itemIdSignal.value);
|
|
520
|
-
});
|
|
521
|
-
};
|
|
522
|
-
|
|
523
|
-
Object.assign(store, {
|
|
524
|
-
mutableIdKeys,
|
|
525
|
-
arraySignal,
|
|
526
|
-
select,
|
|
527
|
-
selectAll,
|
|
528
|
-
upsert,
|
|
529
|
-
drop,
|
|
530
|
-
|
|
531
|
-
observeProperties,
|
|
532
|
-
observeRemovals,
|
|
533
|
-
registerItemMatchLifecycle,
|
|
534
|
-
signalForMutableIdKey,
|
|
535
|
-
});
|
|
536
|
-
return store;
|
|
537
|
-
};
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { effect, signal } from "@preact/signals";
|
|
2
|
-
|
|
3
|
-
export const localStorageSignal = (key) => {
|
|
4
|
-
const initialValue = localStorage.getItem(key);
|
|
5
|
-
|
|
6
|
-
const valueSignal = signal(initialValue === null ? undefined : initialValue);
|
|
7
|
-
effect(() => {
|
|
8
|
-
const value = valueSignal.value;
|
|
9
|
-
if (value === undefined) {
|
|
10
|
-
localStorage.removeItem(key);
|
|
11
|
-
} else {
|
|
12
|
-
localStorage.setItem(key, value);
|
|
13
|
-
}
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
return valueSignal;
|
|
17
|
-
};
|