feat(lib/utils): add react and trees

This commit is contained in:
PalmDevs 2025-05-01 18:21:45 +07:00
parent ca94e6122b
commit 75154b77e8
No known key found for this signature in database
GPG key ID: 6FAE8F8677ACA8BA
3 changed files with 77 additions and 2 deletions

View file

@ -18,11 +18,17 @@
"./logger": {
"default": "./src/logger.ts"
},
"./objects": {
"default": "./src/objects.ts"
},
"./proxy": {
"default": "./src/proxy.ts"
},
"./objects": {
"default": "./src/objects.ts"
"./react": {
"default": "./src/react.ts"
},
"./trees": {
"default": "./src/trees.ts"
},
"./types": {
"types": "./src/types.ts"

23
lib/utils/src/react.ts Normal file
View file

@ -0,0 +1,23 @@
import { React } from '@revenge-mod/react'
import { type SearchFilter, findInTree } from './trees'
import type { ReactNode } from 'react'
export function useIsFirstRender() {
let firstRender = false
React.useEffect(() => {
firstRender = true
}, [])
return firstRender
}
const ReactFiberWalkable = new Set(['props', 'children', 'child', 'sibling'])
export function findInReactFiber(tree: Extract<ReactNode, { props: unknown }>, filter: SearchFilter): any {
return findInTree(tree, filter, {
walkable: ReactFiberWalkable,
})
}

46
lib/utils/src/trees.ts Normal file
View file

@ -0,0 +1,46 @@
export type SearchTree = Record<string, any>
export type SearchFilter = (tree: SearchTree) => boolean
export interface FindInTreeOptions {
/**
* A set of keys to search for in the tree.
*/
walkable?: Set<string>
/**
* A set of keys to ignore when searching the tree.
*/
ignore?: Set<string>
/**
* The maximum depth to search in the tree.
*
* @default 100
*/
maxDepth?: number
}
export function findInTree(tree: SearchTree, filter: SearchFilter, opts?: FindInTreeOptions): any | undefined {
type StackItem = [node: any, depth: number]
const stack: StackItem[] = [[tree, 0]]
const maxDepth = opts?.maxDepth ?? 100
while (stack.length > 0) {
const [node, depth] = stack.pop()!
if (depth > maxDepth || !node) continue
if (filter(node)) return node
const isArray = Array.isArray(node)
const keys = isArray ? node : Object.keys(node)
for (const key of keys) {
const item = isArray ? key : node[key]
if (typeof item !== 'object' || item == null) continue
if (!isArray && opts?.walkable?.size && !opts.walkable?.has(key)) continue
if (!isArray && opts?.ignore?.has(key)) continue
stack.push([item, depth + 1])
}
}
}