Created
March 4, 2024 10:26
-
-
Save keyurparalkar/176a59c555022cc8b532dd325a34262c to your computer and use it in GitHub Desktop.
Recursive Tree component
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
import styled from "styled-components"; | |
import { ReactElement, useState } from "react"; | |
type Tree = { | |
id: string; | |
name: string; | |
icons?: JSX.Element[]; | |
children?: Tree[]; | |
}; | |
type RecursiveTreeProps = { | |
tree: Tree; | |
}; | |
interface CustomDetailsProps extends Omit<Tree, "id"> { | |
renderTree: ReactElement; | |
} | |
const StyledUnorderedList = styled.ul` | |
ul, | |
li { | |
list-style: none; | |
margin: 0; | |
padding: 0; | |
} | |
ul { | |
margin-left: 0.8rem; | |
} | |
`; | |
const StyledDetails = styled.details<{ hasIcons: boolean | undefined }>` | |
& summary { | |
text-align: left; | |
} | |
& summary.custom-icons { | |
display: flex; | |
align-items: center; | |
list-style: none; | |
& span { | |
margin-left: 0.525rem; | |
} | |
} | |
// Below styles are for the border around the details element =================== | |
${(props) => | |
props?.hasIcons && | |
` | |
& ul { | |
padding-left: 0.625rem; | |
border-left: 2px dashed white; | |
} | |
& ul li { | |
position: relative; | |
&::before { | |
content: "--"; | |
display: block; | |
height: 20px; | |
width: 13px; | |
/* border: 2px solid red; */ | |
position: absolute; | |
left: -1.5%; | |
} | |
} | |
`}// ============================================================================ | |
`; | |
const CustomDetails = (props: CustomDetailsProps) => { | |
const { icons, name, renderTree } = props; | |
const [isOpen, setIsOpen] = useState(false); | |
const hasIcons = icons && icons.length > 0; | |
const handleDrawerOpen = ( | |
e: React.SyntheticEvent<HTMLDetailsElement, ToggleEvent> | |
) => { | |
// This stops event bubbling; | |
e.stopPropagation(); | |
setIsOpen(e.nativeEvent.newState === "open" ? true : false); | |
}; | |
return ( | |
<StyledDetails onToggle={handleDrawerOpen} hasIcons={hasIcons}> | |
<summary className={hasIcons ? "custom-icons" : undefined}> | |
{hasIcons && (isOpen ? icons[1] : icons[0])} | |
<span>{name}</span> | |
</summary> | |
{renderTree} | |
</StyledDetails> | |
); | |
}; | |
const RecursiveTree = (props: RecursiveTreeProps) => { | |
const { tree } = props; | |
return ( | |
<StyledUnorderedList> | |
{tree?.children && | |
tree.children.map((item) => ( | |
<li key={`key-${item.id}`}> | |
<CustomDetails | |
icons={item.icons} | |
name={item.name} | |
renderTree={<RecursiveTree tree={item} />} | |
/> | |
</li> | |
))} | |
</StyledUnorderedList> | |
); | |
}; | |
export default RecursiveTree; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment