-
-
Notifications
You must be signed in to change notification settings - Fork 2.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor(devtools): update element selection for the x-ray feature (#…
- Loading branch information
Showing
10 changed files
with
307 additions
and
307 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
--- | ||
"@refinedev/devtools": patch | ||
--- | ||
|
||
refactor(devtools): check both parent and child nodes for representation | ||
|
||
Previously, Refine Devtools's X-Ray feature looked for the representation of the components by looking at the parent nodes until a proper `stateNode` was found. This was problematic when the parent node was not a proper HTML element. A lack of type checking caused the feature to break in runtime in some cases. | ||
|
||
Adding only a type check for the `stateNode` is not enough since there may be cases where there are no proper HTML elements in the parent nodes. This change adds a check for the child nodes as well. This way, the feature will look for the representation in both the parent and child nodes. | ||
|
||
First check for a representation node will be done in the child nodes. If a proper representation is not found, an element will be searched in the parent nodes. If a no proper representation is found in the parent nodes, `document.body` will be used as the representation. | ||
|
||
[Resolves #6219](https://github.com/refinedev/refine/issues/6219) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
--- | ||
"@refinedev/devtools": patch | ||
--- | ||
|
||
fix(devtools): styling issues in the X-Ray feature | ||
|
||
A minimum size was set for the X-Ray feature's overlay to prevent it from being too small. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,157 @@ | ||
import { | ||
getElementFromFiber, | ||
getFiberFromElement, | ||
getFirstFiberHasName, | ||
getFirstStateNodeFiber, | ||
getNameFromFiber, | ||
getParentOfFiber, | ||
} from "@aliemir/dom-to-fiber-utils"; | ||
|
||
type Fiber = Exclude<ReturnType<typeof getFiberFromElement>, null>; | ||
|
||
export type SelectableElement = { | ||
element: HTMLElement; | ||
name: string; | ||
}; | ||
|
||
const getChildOfFiber = (fiber: Fiber | null) => { | ||
if (!fiber) { | ||
return null; | ||
} | ||
|
||
return fiber.child; | ||
}; | ||
|
||
const getFirstHTMLElementFromFiberByChild = (fiber: Fiber | null) => { | ||
let child = fiber; | ||
|
||
while (child) { | ||
const element = getElementFromFiber(child); | ||
if (element && element instanceof HTMLElement) { | ||
return element; | ||
} | ||
|
||
child = getChildOfFiber(child) as Fiber; | ||
} | ||
|
||
return null; | ||
}; | ||
|
||
const getFirstHTMLElementFromFiberByParent = (fiber: Fiber | null) => { | ||
let parent = fiber; | ||
|
||
while (parent) { | ||
const element = getElementFromFiber(parent); | ||
if (element && element instanceof HTMLElement) { | ||
return element; | ||
} | ||
|
||
parent = getParentOfFiber(parent) as Fiber; | ||
} | ||
|
||
return null; | ||
}; | ||
|
||
const getFirstHTMLElementFromFiber = ( | ||
fiber: Fiber | null, | ||
): [element: HTMLElement, "child" | "parent" | "body"] => { | ||
let element = getFirstHTMLElementFromFiberByChild(fiber); | ||
|
||
if (element) { | ||
return [element, "child"]; | ||
} | ||
|
||
element = getFirstHTMLElementFromFiberByParent(fiber); | ||
|
||
if (element) { | ||
return [element, "parent"]; | ||
} | ||
|
||
return [document.body, "body"]; | ||
}; | ||
|
||
const selectFiber = (start: Fiber | null, activeTraceItems: string[]) => { | ||
let fiber = start; | ||
let firstParentOfNodeWithName: Fiber | null = null; | ||
let fiberWithStateNode: Fiber | null = null; | ||
|
||
let acceptedName = false; | ||
|
||
while (!acceptedName && fiber) { | ||
// Get the first fiber node that has a name (look up the tree) | ||
firstParentOfNodeWithName = getFirstFiberHasName(fiber); | ||
// Get the first fiber node that has a state node (look up the tree) | ||
fiberWithStateNode = getFirstStateNodeFiber(firstParentOfNodeWithName); | ||
acceptedName = activeTraceItems.includes( | ||
getNameFromFiber(firstParentOfNodeWithName) ?? "", | ||
); | ||
if (!acceptedName) { | ||
fiber = getParentOfFiber(fiber); | ||
} | ||
} | ||
|
||
if (fiberWithStateNode && firstParentOfNodeWithName) { | ||
return { | ||
stateNode: fiberWithStateNode, | ||
nameFiber: firstParentOfNodeWithName, | ||
}; | ||
} | ||
return { | ||
stateNode: null, | ||
nameFiber: null, | ||
}; | ||
}; | ||
|
||
export const filterInvisibleNodes = (nodes: SelectableElement[]) => { | ||
return nodes.filter( | ||
(item) => item.element.offsetWidth > 0 && item.element.offsetHeight > 0, | ||
); | ||
}; | ||
|
||
export const getUniqueNodes = (nodes: SelectableElement[]) => { | ||
const uniques: SelectableElement[] = []; | ||
|
||
nodes.forEach((node) => { | ||
const isElementExist = uniques.find( | ||
(item) => item.element === node.element && item.name === node.name, | ||
); | ||
if (!isElementExist) { | ||
uniques.push(node); | ||
} | ||
}); | ||
|
||
return uniques; | ||
}; | ||
|
||
export const traverseDom = ( | ||
node: HTMLElement | null, | ||
activeTraceItems: string[], | ||
): SelectableElement[] => { | ||
if (!node) { | ||
return []; | ||
} | ||
|
||
const items: SelectableElement[] = []; | ||
|
||
const fiber = getFiberFromElement(node); | ||
const targetFiber = selectFiber(fiber, activeTraceItems); | ||
|
||
if (targetFiber.nameFiber) { | ||
const [element] = getFirstHTMLElementFromFiber(targetFiber.nameFiber); | ||
const name = getNameFromFiber(targetFiber.nameFiber); | ||
if (element && name) { | ||
items.push({ | ||
element, | ||
name, | ||
}); | ||
} | ||
} | ||
|
||
for (let i = 0; i < node?.children?.length ?? 0; i++) { | ||
items.push( | ||
...traverseDom(node.children[i] as HTMLElement, activeTraceItems), | ||
); | ||
} | ||
|
||
return items; | ||
}; |
Oops, something went wrong.