Skip to content

Instantly share code, notes, and snippets.

@mathis-m
Created October 16, 2023 21:36
Show Gist options
  • Save mathis-m/5c6e23e91f3cfd088c5a4cb3a2eec030 to your computer and use it in GitHub Desktop.
Save mathis-m/5c6e23e91f3cfd088c5a4cb3a2eec030 to your computer and use it in GitHub Desktop.
Tree Renderer - with conncetions
import "./styles.css";
import React, { FC } from "react";
interface INode {
text: string;
children: INode[];
}
const Row: FC<{
node: INode;
slotsBefore: ("empty" | "vertical" | "small-empty")[];
isLastSibling: boolean;
isRoot: boolean;
}> = ({ node, slotsBefore, isRoot, isLastSibling }) => {
return (
<div
style={{
display: "grid",
gridTemplateColumns: [
...slotsBefore.map((slot) =>
slot === "small-empty" ? "10px" : "20px"
),
isRoot ? "1fr" : "10px 1fr"
].join(" ")
}}
>
{slotsBefore.map((slot) =>
slot === "empty" || slot === "small-empty" ? (
<div />
) : (
<div
style={{
borderLeft: "1px solid black"
}}
/>
)
)}
{!isRoot && (
<div
key="connector"
style={{
display: "grid",
gridTemplateColumns: "1fr",
gridTemplateRows: "1fr 1fr"
}}
>
<div
style={{
borderBottom: "1px solid black",
borderLeft: "1px solid black"
}}
/>
<div
style={{
borderLeft: isLastSibling ? undefined : "1px solid black"
}}
/>
</div>
)}
<div key="node" style={{ padding: "5px 0px" }}>
{node.text}
</div>
</div>
);
};
const NodeRenderer: FC<{
slotsBefore: ("empty" | "vertical" | "small-empty")[];
node: INode;
isLastSibling: boolean;
rowIdx: number;
isRoot: boolean;
}> = ({ node, isLastSibling, rowIdx, isRoot, slotsBefore }) => {
return (
<>
<Row
key={`row-${rowIdx}`}
node={node}
slotsBefore={slotsBefore}
isLastSibling={isLastSibling}
isRoot={isRoot}
/>
{node.children.map((x, i) => {
const isChildLastSibling = i === node.children.length - 1;
return (
<NodeRenderer
slotsBefore={
isRoot
? ["small-empty"]
: [...slotsBefore, isLastSibling ? "empty" : "vertical"]
}
key={`row-${rowIdx + i + 1}`}
node={x}
rowIdx={i + rowIdx + 1}
isLastSibling={isChildLastSibling}
isRoot={false}
/>
);
})}
</>
);
};
const Tree: FC<{ root: INode }> = ({ root }) => {
return (
<div>
<NodeRenderer
slotsBefore={[]}
node={root}
isLastSibling={true}
rowIdx={0}
isRoot={true}
/>
</div>
);
};
const root: INode = {
text: "Root",
children: [
{
text: "Node 1",
children: [
{
text: "Nested 1.1",
children: []
},
{
text: "Nested 1.2",
children: [
{
text: "Nested 1.2.1",
children: []
},
{
text: "Nested 1.2.2",
children: []
}
]
}
]
},
{
text: "Node 2",
children: [
{
text: "Nested 2.1",
children: [
{
text: "Nested 2.1.1",
children: [
{
text: "Nested 2.1.1.1",
children: []
}
]
},
{
text: "Nested 2.1.2",
children: []
}
]
}
]
},
{
text: "Node 3",
children: [
{
text: "Nested 3.1",
children: []
}
]
}
]
};
export default function App() {
return <Tree root={root} />;
}
@mathis-m
Copy link
Author

grafik

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment