-
Notifications
You must be signed in to change notification settings - Fork 171
/
ref.ts
74 lines (63 loc) · 1.7 KB
/
ref.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
/* eslint-disable no-param-reassign */
import type * as React from 'react';
import type { ReactNode } from 'react';
import { isValidElement } from 'react';
import { isForwardRef, isFragment, isMemo } from 'react-is';
import useMemo from './hooks/useMemo';
export function fillRef<T>(ref: React.Ref<T>, node: T) {
if (typeof ref === 'function') {
ref(node);
} else if (typeof ref === 'object' && ref && 'current' in ref) {
(ref as any).current = node;
}
}
/**
* Merge refs into one ref function to support ref passing.
*/
export function composeRef<T>(...refs: React.Ref<T>[]): React.Ref<T> {
const refList = refs.filter(ref => ref);
if (refList.length <= 1) {
return refList[0];
}
return (node: T) => {
refs.forEach(ref => {
fillRef(ref, node);
});
};
}
export function useComposeRef<T>(...refs: React.Ref<T>[]): React.Ref<T> {
return useMemo(
() => composeRef(...refs),
refs,
(prev, next) =>
prev.length !== next.length || prev.every((ref, i) => ref !== next[i]),
);
}
export const supportRef = <T>(value: any): value is React.RefAttributes<T> => {
if (isFragment(value)) {
return false;
}
if (isForwardRef(value)) {
return true;
}
const type = isMemo(value) ? value.type.type : value.type;
// Function component node
if (typeof type === 'function' && !type.prototype?.render) {
return false;
}
// Class component
if (typeof value === 'function' && !value.prototype?.render) {
return false;
}
return true;
};
export function supportNodeRef(node: ReactNode): boolean {
if (!isValidElement(node)) {
return false;
}
if (isFragment(node)) {
return false;
}
return supportRef(node);
}
/* eslint-enable */