mirror of
https://github.com/bendtherules/react-fiber-traverse.git
synced 2026-08-18 13:52:36 +00:00
140 lines
3.3 KiB
TypeScript
140 lines
3.3 KiB
TypeScript
import { FiberNode } from "./mocked-types";
|
|
import { isNodeNotHtmlLike } from "./utils";
|
|
|
|
/**
|
|
* Find node by component name, till first match.
|
|
*
|
|
* Matches against class and function name, doesn't match html-like nodes.
|
|
* Returns null if no match is found.
|
|
*
|
|
* @note Highest chance of collision, least data access needed.
|
|
* Different components with same name will collide.
|
|
* Needs access to component name.
|
|
*
|
|
* @example
|
|
* // returns FiberNode for first usage of 'AccordionMenu'
|
|
* findNodeByComponentName(startNode, "AccordionMenu");
|
|
*
|
|
*/
|
|
function findNodeByComponentName(
|
|
node: FiberNode | null,
|
|
expectedName: string
|
|
): FiberNode | null {
|
|
if (node === null) {
|
|
return null;
|
|
}
|
|
|
|
if (isNodeNotHtmlLike(node) && node.type.name === expectedName) {
|
|
return node;
|
|
}
|
|
|
|
{
|
|
const returnVal = findNodeByComponentName(node.child, expectedName);
|
|
if (returnVal !== null) {
|
|
return returnVal;
|
|
}
|
|
}
|
|
{
|
|
const returnVal = findNodeByComponentName(node.sibling, expectedName);
|
|
if (returnVal !== null) {
|
|
return returnVal;
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Find node by component (i.e. class or function by reference), till first match.
|
|
*
|
|
* Matches against class and function by reference.
|
|
* Returns null if no match is found.
|
|
*
|
|
* @note Medium chance of collision, medium data access needed.
|
|
* This is safer than findNodeByComponentName, as different components with the same name won't collide.
|
|
* But, two instances of the same component will still collide.
|
|
* Needs access to component class or function.
|
|
*
|
|
* @example
|
|
* // returns FiberNode for first usage of AccordionMenu
|
|
* findNodeByComponent(startNode, AccordionMenu);
|
|
*
|
|
*/
|
|
function findNodeByComponent(
|
|
node: FiberNode | null,
|
|
expectedClassOrFunction: React.ComponentType
|
|
): FiberNode | null {
|
|
if (node === null) {
|
|
return null;
|
|
}
|
|
|
|
if (isNodeNotHtmlLike(node) && node.type === expectedClassOrFunction) {
|
|
return node;
|
|
}
|
|
|
|
{
|
|
const returnVal = findNodeByComponent(node.child, expectedClassOrFunction);
|
|
if (returnVal !== null) {
|
|
return returnVal;
|
|
}
|
|
}
|
|
{
|
|
const returnVal = findNodeByComponent(
|
|
node.sibling,
|
|
expectedClassOrFunction
|
|
);
|
|
if (returnVal !== null) {
|
|
return returnVal;
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Find node by component instance ref, till first match.
|
|
*
|
|
* Matches against class instances by reference.
|
|
* Returns null if no match is found.
|
|
*
|
|
* @note Least chance of collision, maximum data access needed.
|
|
* Needs access to component instance (through React ref usually).
|
|
*
|
|
* @example
|
|
* // menuRef=createRef(); <AccordionMenu ref={menuRef}>
|
|
* findNodeByComponentRef(startNode, menuRef.current);
|
|
*
|
|
*/
|
|
function findNodeByComponentRef(
|
|
node: FiberNode | null,
|
|
expectedClassInstance: React.Component
|
|
): FiberNode | null {
|
|
if (node === null) {
|
|
return null;
|
|
}
|
|
|
|
if (isNodeNotHtmlLike(node) && node.stateNode === expectedClassInstance) {
|
|
return node;
|
|
}
|
|
|
|
{
|
|
const returnVal = findNodeByComponentRef(node.child, expectedClassInstance);
|
|
if (returnVal !== null) {
|
|
return returnVal;
|
|
}
|
|
}
|
|
{
|
|
const returnVal = findNodeByComponentRef(
|
|
node.sibling,
|
|
expectedClassInstance
|
|
);
|
|
if (returnVal !== null) {
|
|
return returnVal;
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
export { findNodeByComponentName, findNodeByComponent, findNodeByComponentRef };
|