@bento/listbox 0.1.2

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/src/utils.ts ADDED
@@ -0,0 +1,57 @@
1
+ /* v8 ignore next */
2
+ import React, { type ForwardedRef, useEffect, useRef } from 'react';
3
+
4
+ /**
5
+ * NOTE: This utility will be moved to the new use-collection package.
6
+ * Safe wrapper for React Aria's useObjectRef that handles test environments where refs are not extensible.
7
+ *
8
+ * **Critical for Vitest Browser Mode Testing**: When running tests in Vitest's browser mode with Playwright,
9
+ * the test environment can freeze or make objects non-extensible. React Aria's `useObjectRef` attempts to
10
+ * dynamically add properties to ref objects, which fails with "Cannot add property current, object is not extensible"
11
+ * in these constrained test environments.
12
+ *
13
+ * **Technical Details:**
14
+ * - Vitest browser mode uses Playwright's Chrome DevTools Protocol for test execution
15
+ * - The V8 engine's security model can freeze objects during test isolation
16
+ * - React Aria's useObjectRef uses `Object.defineProperty()` to add reactive properties to refs
17
+ * - This conflicts with frozen objects in browser testing scenarios
18
+ *
19
+ * **Why This Solution Works:**
20
+ * - Creates an internal ref that's always mutable (created in our controlled environment)
21
+ * - Safely forwards values to the external ref using try/catch for frozen object scenarios
22
+ * - Maintains the same ref forwarding behavior as React Aria's useObjectRef in normal environments
23
+ * - Gracefully degrades in test environments without breaking functionality
24
+ *
25
+ * **Production Impact**: Zero. Object freezing only occurs in specific test configurations.
26
+ * In production and development, this behaves identically to React Aria's useObjectRef.
27
+ *
28
+ * @template T - The type of the ref element
29
+ * @param {React.ForwardedRef<T>} ref - The forwarded ref to handle safely
30
+ * @returns {React.RefObject<T>} A safe ref object that works in all environments including frozen test contexts
31
+ * @public
32
+ */
33
+ export function useSafeObjectRef<T>(ref: ForwardedRef<T>): React.RefObject<T> {
34
+ const internalRef = useRef<T>(null);
35
+
36
+ useEffect(function updateForwardedRef() {
37
+ const current = internalRef.current;
38
+
39
+ if (typeof ref === 'function') {
40
+ ref(current);
41
+ } else if (ref && 'current' in ref) {
42
+ try {
43
+ (ref as React.MutableRefObject<T | null>).current = current;
44
+ /* v8 ignore start */
45
+ } catch {
46
+ //
47
+ // Silently ignore errors in test environments where objects might be frozen.
48
+ // This specifically handles Vitest browser mode with Playwright where the V8 engine
49
+ // may freeze ref objects during test isolation, preventing dynamic property assignment.
50
+ //
51
+ }
52
+ /* v8 ignore stop */
53
+ }
54
+ });
55
+
56
+ return internalRef;
57
+ }