@jsenv/navi 0.0.1 → 0.1.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 (138) hide show
  1. package/dist/jsenv_navi.js +22954 -0
  2. package/index.js +66 -16
  3. package/package.json +22 -11
  4. package/src/actions.js +50 -26
  5. package/src/browser_integration/browser_integration.js +31 -6
  6. package/src/browser_integration/via_history.js +42 -9
  7. package/src/components/action_execution/render_actionable_component.jsx +6 -4
  8. package/src/components/action_execution/use_action.js +51 -282
  9. package/src/components/action_execution/use_execute_action.js +106 -92
  10. package/src/components/action_execution/use_run_on_mount.js +9 -0
  11. package/src/components/action_renderer.jsx +21 -32
  12. package/src/components/demos/0_button_demo.html +574 -103
  13. package/src/components/demos/10_column_reordering_debug.html +277 -0
  14. package/src/components/demos/11_table_selection_debug.html +432 -0
  15. package/src/components/demos/1_checkbox_demo.html +579 -202
  16. package/src/components/demos/2_input_textual_demo.html +81 -138
  17. package/src/components/demos/3_radio_demo.html +0 -2
  18. package/src/components/demos/4_select_demo.html +19 -23
  19. package/src/components/demos/6_tablist_demo.html +77 -0
  20. package/src/components/demos/7_table_selection_demo.html +176 -0
  21. package/src/components/demos/8_table_fixed_headers_demo.html +584 -0
  22. package/src/components/demos/9_table_column_drag_demo.html +325 -0
  23. package/src/components/demos/action/0_button_demo.html +2 -4
  24. package/src/components/demos/action/1_input_text_demo.html +643 -222
  25. package/src/components/demos/action/3_details_demo.html +146 -115
  26. package/src/components/demos/action/4_input_checkbox_demo.html +442 -322
  27. package/src/components/demos/action/5_input_checkbox_state_demo.html +270 -0
  28. package/src/components/demos/action/6_checkbox_list_demo.html +304 -72
  29. package/src/components/demos/action/7_radio_list_demo.html +310 -170
  30. package/src/components/demos/action/{8_editable_text_demo.html → 8_editable_demo.html} +65 -76
  31. package/src/components/demos/action/9_link_demo.html +84 -62
  32. package/src/components/demos/ui_transition/0_action_renderer_ui_transition_demo.html +695 -0
  33. package/src/components/demos/ui_transition/1_nested_ui_transition_demo.html +429 -0
  34. package/src/components/demos/ui_transition/2_height_transition_test.html +295 -0
  35. package/src/components/details/details.jsx +62 -64
  36. package/src/components/edition/editable.jsx +186 -0
  37. package/src/components/field/README.md +247 -0
  38. package/src/components/{input → field}/button.jsx +151 -130
  39. package/src/components/field/checkbox_list.jsx +184 -0
  40. package/src/components/{collect_form_element_values.js → field/collect_form_element_values.js} +7 -4
  41. package/src/components/{input → field}/field_css.js +4 -1
  42. package/src/components/field/form.jsx +211 -0
  43. package/src/components/{input → field}/input.jsx +1 -0
  44. package/src/components/{input → field}/input_checkbox.jsx +132 -155
  45. package/src/components/{input → field}/input_radio.jsx +135 -46
  46. package/src/components/{input → field}/input_textual.jsx +247 -173
  47. package/src/components/field/label.jsx +32 -0
  48. package/src/components/field/radio_list.jsx +182 -0
  49. package/src/components/{input → field}/select.jsx +17 -32
  50. package/src/components/field/use_action_events.js +132 -0
  51. package/src/components/field/use_form_events.js +55 -0
  52. package/src/components/field/use_ui_state_controller.js +506 -0
  53. package/src/components/item_tracker/README.md +461 -0
  54. package/src/components/item_tracker/use_isolated_item_tracker.jsx +209 -0
  55. package/src/components/item_tracker/use_isolated_item_tracker_demo.html +148 -0
  56. package/src/components/item_tracker/use_isolated_item_tracker_demo.jsx +460 -0
  57. package/src/components/item_tracker/use_item_tracker.jsx +143 -0
  58. package/src/components/item_tracker/use_item_tracker_demo.html +207 -0
  59. package/src/components/item_tracker/use_item_tracker_demo.jsx +216 -0
  60. package/src/components/keyboard_shortcuts/active_keyboard_shortcuts.jsx +87 -0
  61. package/src/components/keyboard_shortcuts/aria_key_shortcuts.js +61 -0
  62. package/src/components/keyboard_shortcuts/keyboard_key_meta.js +17 -0
  63. package/src/components/keyboard_shortcuts/keyboard_shortcuts.js +371 -0
  64. package/src/components/link/link.jsx +65 -102
  65. package/src/components/link/link_with_icon.jsx +52 -0
  66. package/src/components/loader/loader_background.jsx +85 -64
  67. package/src/components/loader/rectangle_loading.jsx +38 -19
  68. package/src/components/route.jsx +8 -4
  69. package/src/components/selection/selection.jsx +1583 -0
  70. package/src/components/svg/font_sized_svg.jsx +45 -0
  71. package/src/components/svg/icon_and_text.jsx +21 -0
  72. package/src/components/svg/svg_mask_overlay.jsx +105 -0
  73. package/src/components/table/drag/table_drag.jsx +506 -0
  74. package/src/components/table/resize/table_resize.jsx +650 -0
  75. package/src/components/table/resize/table_size.js +43 -0
  76. package/src/components/table/selection/table_selection.js +106 -0
  77. package/src/components/table/selection/table_selection.jsx +203 -0
  78. package/src/components/table/sticky/sticky_group.js +354 -0
  79. package/src/components/table/sticky/table_sticky.js +25 -0
  80. package/src/components/table/sticky/table_sticky.jsx +501 -0
  81. package/src/components/table/table.jsx +721 -0
  82. package/src/components/table/table_css.js +211 -0
  83. package/src/components/table/table_ui.jsx +49 -0
  84. package/src/components/table/use_cells_and_columns.js +90 -0
  85. package/src/components/table/use_object_array_to_cells.js +46 -0
  86. package/src/components/table/z_indexes.js +23 -0
  87. package/src/components/tablist/tablist.jsx +99 -0
  88. package/src/components/text/overflow.jsx +15 -0
  89. package/src/components/text/text_and_count.jsx +28 -0
  90. package/src/components/ui_transition.jsx +128 -0
  91. package/src/components/use_auto_focus.js +58 -7
  92. package/src/components/use_batch_during_render.js +33 -0
  93. package/src/components/use_debounce_true.js +7 -7
  94. package/src/components/use_dependencies_diff.js +35 -0
  95. package/src/components/use_focus_group.js +4 -3
  96. package/src/components/use_initial_value.js +8 -34
  97. package/src/components/use_signal_sync.js +1 -1
  98. package/src/components/use_stable_callback.js +68 -0
  99. package/src/components/use_state_array.js +16 -9
  100. package/src/docs/actions.md +22 -0
  101. package/src/notes.md +33 -12
  102. package/src/route/route.js +97 -47
  103. package/src/store/resource_graph.js +2 -1
  104. package/src/store/tests/{resource_graph_dependencies.test.js → resource_graph_dependencies.test_manual.js} +13 -13
  105. package/src/utils/is_signal.js +20 -0
  106. package/src/utils/stringify_for_display.js +4 -23
  107. package/src/validation/constraints/confirm_constraint.js +14 -0
  108. package/src/validation/constraints/create_unique_value_constraint.js +27 -0
  109. package/src/validation/constraints/native_constraints.js +313 -0
  110. package/src/validation/constraints/readonly_constraint.js +36 -0
  111. package/src/validation/constraints/single_space_constraint.js +13 -0
  112. package/src/validation/custom_constraint_validation.js +599 -0
  113. package/src/validation/custom_message.js +18 -0
  114. package/src/validation/demos/browser_style.png +0 -0
  115. package/src/validation/demos/form_validation_demo.html +142 -0
  116. package/src/validation/demos/form_validation_demo_preact.html +87 -0
  117. package/src/validation/demos/form_validation_native_popover_demo.html +168 -0
  118. package/src/validation/demos/form_validation_vs_native_demo.html +172 -0
  119. package/src/validation/demos/validation_message_demo.html +203 -0
  120. package/src/validation/hooks/use_constraints.js +23 -0
  121. package/src/validation/hooks/use_custom_validation_ref.js +73 -0
  122. package/src/validation/hooks/use_validation_message.js +19 -0
  123. package/src/validation/validation_message.js +741 -0
  124. package/src/components/editable_text/editable_text.jsx +0 -96
  125. package/src/components/form.jsx +0 -144
  126. package/src/components/input/checkbox_list.jsx +0 -294
  127. package/src/components/input/field.jsx +0 -61
  128. package/src/components/input/radio_list.jsx +0 -283
  129. package/src/components/input/use_form_event.js +0 -20
  130. package/src/components/input/use_on_change.js +0 -12
  131. package/src/components/selection/selection.js +0 -5
  132. package/src/components/selection/selection_context.jsx +0 -262
  133. package/src/components/shortcut/shortcut_context.jsx +0 -390
  134. package/src/components/use_action_events.js +0 -37
  135. package/src/utils/iterable_weak_set.js +0 -62
  136. /package/src/components/demos/action/{11_nested_shortcuts_demo.html → 11_nested_shortcuts_demo.xhtml} +0 -0
  137. /package/src/components/{shortcut → keyboard_shortcuts}/os.js +0 -0
  138. /package/src/route/{route.test.html → route.xtest.html} +0 -0
@@ -1,390 +0,0 @@
1
- import { canInterceptKeys } from "@jsenv/dom";
2
- import { requestAction } from "@jsenv/validation";
3
- import { createContext } from "preact";
4
- import { useContext, useEffect, useRef, useState } from "preact/hooks";
5
- import { useAction } from "../action_execution/use_action.js";
6
- import { useExecuteAction } from "../action_execution/use_execute_action.js";
7
- import { useActionEvents } from "../use_action_events.js";
8
- import { isMac } from "./os.js";
9
-
10
- import.meta.css = /* css */ `
11
- .navi_shortcut_container {
12
- /* Visually hidden container - doesn't affect layout */
13
- position: absolute;
14
- width: 1px;
15
- height: 1px;
16
- padding: 0;
17
- margin: -1px;
18
- overflow: hidden;
19
- clip: rect(0, 0, 0, 0);
20
- white-space: nowrap;
21
- border: 0;
22
-
23
- /* Ensure it's not interactable */
24
- opacity: 0;
25
- pointer-events: none;
26
- }
27
-
28
- .navi_shortcut_button {
29
- /* Visually hidden but accessible to screen readers */
30
- position: absolute;
31
- width: 1px;
32
- height: 1px;
33
- padding: 0;
34
- margin: -1px;
35
- overflow: hidden;
36
- clip: rect(0, 0, 0, 0);
37
- white-space: nowrap;
38
- border: 0;
39
-
40
- /* Ensure it's not focusable via tab navigation */
41
- opacity: 0;
42
- pointer-events: none;
43
- }
44
- `;
45
-
46
- const ShortcutContext = createContext();
47
- export const useShortcutContext = () => {
48
- return useContext(ShortcutContext);
49
- };
50
-
51
- export const ShortcutProvider = ({
52
- elementRef,
53
- shortcuts,
54
- onActionPrevented,
55
- onActionStart,
56
- onActionAbort,
57
- onActionError,
58
- onActionEnd,
59
- allowConcurrentActions,
60
- children,
61
- }) => {
62
- if (!elementRef) {
63
- throw new Error(
64
- "ShortcutProvider requires an elementRef to attach shortcuts to.",
65
- );
66
- }
67
-
68
- const shortcutElements = [];
69
- shortcuts.forEach((shortcut) => {
70
- const combinationString = useAriaKeyShortcuts(shortcut.key);
71
- shortcutElements.push(
72
- <button
73
- className="navi_shortcut_button"
74
- key={combinationString}
75
- aria-keyshortcuts={combinationString}
76
- tabIndex="-1"
77
- action={shortcut.action}
78
- data-action={shortcut.action.name}
79
- data-confirm-message={shortcut.confirmMessage}
80
- >
81
- {shortcut.description}
82
- </button>,
83
- );
84
- });
85
- const shortcutElementRef = useRef();
86
- const shortcutHiddenElement = (
87
- <div ref={shortcutElementRef} className="navi_shortcut_container">
88
- {shortcutElements}
89
- </div>
90
- );
91
-
92
- const executeAction = useExecuteAction(shortcutElementRef);
93
- const [shortcutActionIsBusy, setShortcutActionIsBusy] = useState(false);
94
- useActionEvents(shortcutElementRef, {
95
- onPrevented: onActionPrevented,
96
- onAction: (actionEvent) => {
97
- // action can be a function or an action object, whem a function we must "wrap" it in a function returning that function
98
- // otherwise setState would call that action immediately
99
- setAction(() => actionEvent.detail.action);
100
- executeAction(actionEvent, { requester: elementRef.current });
101
- },
102
- onStart: (e) => {
103
- if (!allowConcurrentActions) {
104
- setShortcutActionIsBusy(true);
105
- }
106
- onActionStart?.(e);
107
- },
108
- onAbort: (e) => {
109
- setShortcutActionIsBusy(false);
110
- onActionAbort?.(e);
111
- },
112
- onError: (e) => {
113
- setShortcutActionIsBusy(false);
114
- onActionError?.(e);
115
- },
116
- onEnd: (e) => {
117
- setShortcutActionIsBusy(false);
118
- onActionEnd?.(e);
119
- },
120
- });
121
-
122
- const [action, setAction] = useState(null);
123
- for (const shortcut of shortcuts) {
124
- shortcut.action = useAction(shortcut.action);
125
- }
126
-
127
- useKeyboardShortcuts(elementRef, shortcuts, (shortcut, event) => {
128
- if (shortcutActionIsBusy) {
129
- return;
130
- }
131
- event.preventDefault();
132
- const { action } = shortcut;
133
- requestAction(action, {
134
- event,
135
- target: shortcutElementRef.current,
136
- requester: elementRef.current,
137
- confirmMessage: shortcut.confirmMessage,
138
- });
139
- });
140
-
141
- return (
142
- <ShortcutContext.Provider
143
- value={{
144
- shortcutAction: action,
145
- shortcutActionIsBusy,
146
- }}
147
- >
148
- {children}
149
- {shortcutHiddenElement}
150
- </ShortcutContext.Provider>
151
- );
152
- };
153
-
154
- export const useKeyboardShortcuts = (elementRef, shortcuts, onShortcut) => {
155
- const shortcutsRef = useRef(shortcuts);
156
- shortcutsRef.current = shortcuts;
157
-
158
- const onShortcutRef = useRef(onShortcut);
159
- onShortcutRef.current = onShortcut;
160
-
161
- useEffect(() => {
162
- const element = elementRef.current;
163
-
164
- const onKeydown = (event) => {
165
- if (!canInterceptKeys(event)) {
166
- return;
167
- }
168
-
169
- let shortcutFound;
170
- for (const shortcutCandidate of shortcutsRef.current) {
171
- const { enabled = true, key } = shortcutCandidate;
172
- if (!enabled) {
173
- continue;
174
- }
175
-
176
- // Handle platform-specific combination objects
177
- let actualCombination;
178
- let crossPlatformCombination;
179
-
180
- if (typeof key === "object" && key !== null) {
181
- actualCombination = isMac ? key.mac : key.other;
182
- } else {
183
- actualCombination = key;
184
-
185
- // Auto-generate cross-platform combination if needed
186
- if (containsPlatformSpecificKeys(key)) {
187
- crossPlatformCombination = generateCrossPlatformCombination(key);
188
- }
189
- }
190
-
191
- // Check both the actual combination and cross-platform combination
192
- const matchesActual =
193
- actualCombination &&
194
- eventIsMatchingKeyCombination(event, actualCombination);
195
- const matchesCrossPlatform =
196
- crossPlatformCombination &&
197
- crossPlatformCombination !== actualCombination &&
198
- eventIsMatchingKeyCombination(event, crossPlatformCombination);
199
-
200
- if (!matchesActual && !matchesCrossPlatform) {
201
- continue;
202
- }
203
- if (shortcutCandidate.when && !shortcutCandidate.when(event)) {
204
- continue;
205
- }
206
- shortcutFound = shortcutCandidate;
207
- break;
208
- }
209
- if (!shortcutFound) {
210
- return;
211
- }
212
- onShortcutRef.current(shortcutFound, event);
213
- };
214
-
215
- element.addEventListener("keydown", onKeydown);
216
- return () => {
217
- element.removeEventListener("keydown", onKeydown);
218
- };
219
- }, []);
220
- };
221
-
222
- // Configuration for mapping shortcut key names to browser event properties
223
- const modifierKeyMapping = {
224
- metaKey: {
225
- names: ["meta"],
226
- macNames: ["command", "cmd"],
227
- },
228
- ctrlKey: {
229
- names: ["control", "ctrl"],
230
- },
231
- shiftKey: {
232
- names: ["shift"],
233
- },
234
- altKey: {
235
- names: ["alt"],
236
- macNames: ["option"],
237
- },
238
- };
239
- // Maps canonical browser key names to their user-friendly aliases.
240
- // Used for both event matching and ARIA normalization.
241
- const keyMapping = {
242
- " ": { alias: ["space"] },
243
- "escape": { alias: ["esc"] },
244
- "arrowup": { alias: ["up"] },
245
- "arrowdown": { alias: ["down"] },
246
- "arrowleft": { alias: ["left"] },
247
- "arrowright": { alias: ["right"] },
248
- "delete": { alias: ["del"] },
249
- // Platform-specific mappings
250
- ...(isMac
251
- ? { delete: { alias: ["backspace"] } }
252
- : { backspace: { alias: ["delete"] } }),
253
- };
254
- const keyToAriaKeyMapping = {
255
- // Platform-specific ARIA names
256
- command: "meta",
257
- option: "altgraph", // Mac option key uses "altgraph" in ARIA spec
258
-
259
- // Regular keys - platform-specific normalization
260
- delete: isMac ? "backspace" : "delete", // Mac delete key is backspace semantically
261
- backspace: isMac ? "backspace" : "delete",
262
- };
263
-
264
- const eventIsMatchingKeyCombination = (event, keyCombination) => {
265
- const keys = keyCombination.toLowerCase().split("+");
266
-
267
- for (const key of keys) {
268
- let modifierFound = false;
269
-
270
- // Check if this key is a modifier
271
- for (const [eventProperty, config] of Object.entries(modifierKeyMapping)) {
272
- const allNames = [...config.names];
273
-
274
- // Add Mac-specific names only if we're on Mac and they exist
275
- if (isMac && config.macNames) {
276
- allNames.push(...config.macNames);
277
- }
278
-
279
- if (allNames.includes(key)) {
280
- // Check if the corresponding event property is pressed
281
- if (!event[eventProperty]) {
282
- return false;
283
- }
284
- modifierFound = true;
285
- break;
286
- }
287
- }
288
- if (modifierFound) {
289
- continue;
290
- }
291
-
292
- // If it's not a modifier, check if it matches the actual key
293
- if (!isSameKey(event.key, key)) {
294
- return false;
295
- }
296
- }
297
- return true;
298
- };
299
-
300
- const isSameKey = (browserEventKey, key) => {
301
- browserEventKey = browserEventKey.toLowerCase();
302
- key = key.toLowerCase();
303
-
304
- if (browserEventKey === key) {
305
- return true;
306
- }
307
-
308
- // Check if either key is an alias for the other
309
- for (const [canonicalKey, config] of Object.entries(keyMapping)) {
310
- const allKeys = [canonicalKey, ...config.alias];
311
- if (allKeys.includes(browserEventKey) && allKeys.includes(key)) {
312
- return true;
313
- }
314
- }
315
-
316
- return false;
317
- };
318
-
319
- const normalizeKey = (key) => {
320
- key = key.toLowerCase();
321
-
322
- // Find the canonical form for this key
323
- for (const [canonicalKey, config] of Object.entries(keyMapping)) {
324
- const allKeys = [canonicalKey, ...config.alias];
325
- if (allKeys.includes(key)) {
326
- return canonicalKey;
327
- }
328
- }
329
-
330
- return key;
331
- };
332
-
333
- const normalizeKeyCombination = (combination) => {
334
- const lowerCaseCombination = combination.toLowerCase();
335
- const keys = lowerCaseCombination.split("+");
336
-
337
- // First normalize keys to their canonical form, then apply ARIA mapping
338
- for (let i = 0; i < keys.length; i++) {
339
- let key = normalizeKey(keys[i]);
340
-
341
- // Then apply ARIA-specific mappings if they exist
342
- if (keyToAriaKeyMapping[key]) {
343
- key = keyToAriaKeyMapping[key];
344
- }
345
-
346
- keys[i] = key;
347
- }
348
-
349
- return keys.join("+");
350
- };
351
-
352
- // http://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Reference/Attributes/aria-keyshortcuts
353
- const useAriaKeyShortcuts = (key) => {
354
- let actualCombination;
355
-
356
- // Handle platform-specific combination objects
357
- if (typeof key === "object" && key !== null) {
358
- actualCombination = isMac ? key.mac : key.other;
359
- } else {
360
- actualCombination = key;
361
- }
362
-
363
- if (actualCombination) {
364
- return normalizeKeyCombination(actualCombination);
365
- }
366
-
367
- return "";
368
- };
369
-
370
- const containsPlatformSpecificKeys = (combination) => {
371
- const lowerCombination = combination.toLowerCase();
372
- const macSpecificKeys = ["command", "cmd"];
373
-
374
- return macSpecificKeys.some((key) => lowerCombination.includes(key));
375
- };
376
-
377
- const generateCrossPlatformCombination = (combination) => {
378
- let crossPlatform = combination;
379
-
380
- if (isMac) {
381
- // No need to convert anything TO Windows/Linux-specific format since we're on Mac
382
- return null;
383
- }
384
-
385
- // If not on Mac but combination contains Mac-specific keys, generate Windows equivalent
386
- crossPlatform = crossPlatform.replace(/\bcommand\b/gi, "control");
387
- crossPlatform = crossPlatform.replace(/\bcmd\b/gi, "control");
388
-
389
- return crossPlatform;
390
- };
@@ -1,37 +0,0 @@
1
- import { useLayoutEffect } from "preact/hooks";
2
- import { addManyEventListeners } from "../utils/add_many_event_listeners.js";
3
-
4
- export const useActionEvents = (
5
- elementRef,
6
- {
7
- /**
8
- * @param {Event} e - L'événement original
9
- * @param {"form_reset" | "blur_invalid" | "escape_key"} reason - Raison du cancel
10
- */
11
- onCancel,
12
- onPrevented,
13
- onAction,
14
- onStart,
15
- onAbort,
16
- onError,
17
- onEnd,
18
- },
19
- ) => {
20
- useLayoutEffect(() => {
21
- const element = elementRef.current;
22
-
23
- return addManyEventListeners(element, {
24
- cancel: (e) => {
25
- onCancel?.(e, e.detail.reason);
26
- },
27
- actionprevented: onPrevented,
28
- action: onAction,
29
- actionstart: onStart,
30
- actionabort: onAbort,
31
- actionerror: (e) => {
32
- onError?.(e.detail.error);
33
- },
34
- actionend: onEnd,
35
- });
36
- }, [onCancel, onPrevented, onAction, onStart, onError, onEnd]);
37
- };
@@ -1,62 +0,0 @@
1
- export const createIterableWeakSet = () => {
2
- const objectWeakRefSet = new Set();
3
-
4
- return {
5
- add: (object) => {
6
- const objectWeakRef = new WeakRef(object);
7
- objectWeakRefSet.add(objectWeakRef);
8
- },
9
-
10
- delete: (object) => {
11
- for (const weakRef of objectWeakRefSet) {
12
- if (weakRef.deref() === object) {
13
- objectWeakRefSet.delete(weakRef);
14
- return true;
15
- }
16
- }
17
- return false;
18
- },
19
-
20
- *[Symbol.iterator]() {
21
- for (const objectWeakRef of objectWeakRefSet) {
22
- const object = objectWeakRef.deref();
23
- if (object === undefined) {
24
- objectWeakRefSet.delete(objectWeakRef);
25
- continue;
26
- }
27
- yield object;
28
- }
29
- },
30
-
31
- has: (object) => {
32
- for (const weakRef of objectWeakRefSet) {
33
- const objectCandidate = weakRef.deref();
34
- if (objectCandidate === undefined) {
35
- objectWeakRefSet.delete(weakRef);
36
- continue;
37
- }
38
- if (objectCandidate === object) {
39
- return true;
40
- }
41
- }
42
- return false;
43
- },
44
-
45
- get size() {
46
- return objectWeakRefSet.size;
47
- },
48
-
49
- getStats: () => {
50
- let alive = 0;
51
- let dead = 0;
52
- for (const weakRef of objectWeakRefSet) {
53
- if (weakRef.deref() !== undefined) {
54
- alive++;
55
- } else {
56
- dead++;
57
- }
58
- }
59
- return { total: objectWeakRefSet.size, alive, dead };
60
- },
61
- };
62
- };
File without changes