import { useMemo, useState } from "react"; import type { HierarchyElement, Hierarchy } from "../types"; import "./HierarchyPanel.css"; interface HierarchyPanelProps { hierarchy?: Hierarchy; } export default function HierarchyPanel({ hierarchy }: HierarchyPanelProps): JSX.Element { const [filter, setFilter] = useState(""); const elements = hierarchy?.elements ?? []; const rows = useMemo(() => { const lower = filter.trim().toLowerCase(); if (!lower) return elements; return elements.filter((element) => matches(element, lower)); }, [elements, filter]); if (elements.length === 0) { return
no hierarchy captured
; } return (
setFilter(e.target.value)} />
{rows.map((element, index) => ( ))}
tag/class id text/desc bounds
{rows.length} of {elements.length}
); } function HierarchyRow({ element }: { element: HierarchyElement }): JSX.Element { const tag = element.tag ?? element.class ?? ""; const text = (element.text ?? element.description ?? "").slice(0, 80); const bounds = element.bounds; return ( {tag} {element.resourceId ?? ""} {text} [{bounds.left},{bounds.top},{bounds.right},{bounds.bottom}] ); } function matches(element: HierarchyElement, needle: string): boolean { const fields = [ element.resourceId, element.text, element.description, element.class, element.tag, ]; for (const value of fields) { if (value && value.toLowerCase().includes(needle)) return true; } if (element.attributes) { for (const value of Object.values(element.attributes)) { if (value.toLowerCase().includes(needle)) return true; } } return false; }