Skip to content

Commit b9c3a90

Browse files
add utils mergeRefs
1 parent 04310b8 commit b9c3a90

File tree

5 files changed

+85
-2
lines changed

5 files changed

+85
-2
lines changed

packages/minimal-shared/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "minimal-shared",
33
"author": "Minimals",
4-
"version": "1.0.2",
4+
"version": "1.0.3",
55
"description": "Shared hooks and utils used by Minimal UI and Zone UI.",
66
"keywords": [
77
"typescript",
@@ -62,7 +62,7 @@
6262
"lint:fix": "eslint --fix \"**/*.{js,jsx,ts,tsx}\"",
6363
"lint:print": "npx eslint --print-config eslint.config.mjs > eslint-current-config.json",
6464
"clean": "rm -rf node_modules .turbo .next out dist build",
65-
"re:build": "pnpm clean && pnpm install && pnpm build",
65+
"re:build": "pnpm clean && pnpm install && pnpm test && pnpm build",
6666
"tsc:print": "npx tsc --showConfig"
6767
},
6868
"dependencies": {

packages/minimal-shared/src/utils/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
export * from './url';
2+
export * from './refs';
23
export * from './font';
34
export * from './color';
45
export * from './object';
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './refs';
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import { mergeRefs } from './refs';
2+
3+
// ----------------------------------------------------------------------
4+
5+
describe('mergeRefs()', () => {
6+
it('1. Should call all function refs with the value', () => {
7+
const ref1 = vi.fn();
8+
const ref2 = vi.fn();
9+
const mergedRef = mergeRefs([ref1, ref2]);
10+
11+
const value = 'test';
12+
mergedRef(value);
13+
14+
expect(ref1).toHaveBeenCalledWith(value);
15+
expect(ref2).toHaveBeenCalledWith(value);
16+
});
17+
18+
it('2. Should handle null and undefined refs gracefully', () => {
19+
const ref1 = vi.fn();
20+
const ref2 = { current: null };
21+
const mergedRef = mergeRefs([ref1, null, ref2, undefined]);
22+
23+
const value = 'test';
24+
mergedRef(value);
25+
26+
expect(ref1).toHaveBeenCalledWith(value);
27+
expect(ref2.current).toBe(value);
28+
});
29+
30+
it('3. Should handle an empty array of refs', () => {
31+
const mergedRef = mergeRefs([]);
32+
33+
const value = 'test';
34+
mergedRef(value);
35+
36+
// No refs to call, so no expectations
37+
});
38+
39+
it('4. Should handle an array with only null or undefined refs', () => {
40+
const mergedRef = mergeRefs([null, undefined]);
41+
42+
const value = 'test';
43+
mergedRef(value);
44+
45+
// No refs to call, so no expectations
46+
});
47+
48+
it('5. Should handle an array with mixed function and object refs', () => {
49+
const ref1 = vi.fn();
50+
const ref2 = { current: null };
51+
const mergedRef = mergeRefs([ref1, ref2]);
52+
53+
const value = 'test';
54+
mergedRef(value);
55+
56+
expect(ref1).toHaveBeenCalledWith(value);
57+
expect(ref2.current).toBe(value);
58+
});
59+
});
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// ----------------------------------------------------------------------
2+
3+
export function mergeRefs<T>(refs: (React.Ref<T> | undefined | null)[]): React.RefCallback<T> {
4+
return (value: T | null) => {
5+
// Early return if there are no refs
6+
if (refs.length === 0) return;
7+
8+
for (const ref of refs) {
9+
// Skip invalid refs
10+
if (!ref) continue;
11+
12+
// Handle function refs
13+
if (typeof ref === 'function') {
14+
ref(value);
15+
}
16+
// Handle object refs with 'current' property
17+
else if ('current' in ref) {
18+
(ref as React.MutableRefObject<T | null>).current = value;
19+
}
20+
}
21+
};
22+
}

0 commit comments

Comments
 (0)