-
Notifications
You must be signed in to change notification settings - Fork 0
/
childrenTraversal.ts
70 lines (61 loc) · 1.84 KB
/
childrenTraversal.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
import * as React from 'react'
function mapChildren(
children: React.ReactNode,
fn: (child: React.ReactElement) => React.ReactElement | null,
): React.ReactNode {
return React.Children.map(children, (child) => {
if (!React.isValidElement(child)) return child
const mapped = fn(child)
if (child.props.children && typeof child.props.children !== 'function') {
const mappedChildren = mapChildren(child.props.children, fn)
return mapped && React.cloneElement(mapped, { children: mappedChildren })
}
return mapped
})
}
function findElement(
root: React.ReactNode,
predicate: (element: React.ReactElement) => boolean,
): React.ReactElement | null {
const initialState: React.ReactElement | null = null
return reduceElements<React.ReactElement | null>(
root,
initialState,
(previous, current) => {
if (previous) return previous
if (predicate(current)) {
return current
}
return null
},
)
}
function findParent(
root: React.ReactNode,
child: React.ReactElement,
): React.ReactElement | null {
return findElement(root, (parentCandidate) => {
const me = parentCandidate.props?.children?.find?.(
(ch: React.ReactNode) => {
return ch === child
},
)
return !!me
})
}
function reduceElements<T>(
children: React.ReactNode,
initialState: T,
reducer: (previousState: T, currentState: React.ReactElement) => T,
): T {
let foldedValue = initialState
React.Children.forEach(children, (child) => {
if (!React.isValidElement(child)) return
foldedValue = reducer(foldedValue, child)
if (child.props.children && typeof child.props.children !== 'function') {
foldedValue = reduceElements(child.props.children, foldedValue, reducer)
}
})
return foldedValue
}
export { mapChildren, reduceElements, findElement, findParent }