|
import React, { useState, useEffect, useContext, useRef } from "react"; |
|
import ReactDOM from "react-dom"; |
|
import { NavLink } from "react-router-dom"; |
|
import styled from "styled-components"; |
|
import "./styles.css"; |
|
|
|
const Context = React.createContext(); |
|
|
|
const useBreadcrumbContext = () => { |
|
const context = useContext(Context); |
|
|
|
if (!context) { |
|
throw new Error("Missing BreadcrumbProvider."); |
|
} |
|
|
|
return context; |
|
}; |
|
|
|
const BreadcrumbProvider = ({ children }) => { |
|
const portalNodeState = useState(); |
|
|
|
return ( |
|
<Context.Provider value={portalNodeState}>{children}</Context.Provider> |
|
); |
|
}; |
|
|
|
const BreadcrumbPortal = ({ children }) => { |
|
const portalNodeRef = useRef(); |
|
const [, setPortalNode] = useBreadcrumbContext(); |
|
|
|
useEffect(() => { |
|
setPortalNode(portalNodeRef.current); |
|
}, []); |
|
|
|
return ( |
|
<nav aria-label="Breadcrumb"> |
|
<Items ref={portalNodeRef} /> |
|
</nav> |
|
); |
|
}; |
|
|
|
const Items = styled.ol` |
|
margin: 0; |
|
padding-left: 0; |
|
list-style: none; |
|
`; |
|
|
|
const Breadcrumb = ({ children, to, ...props }) => { |
|
const [portalNode] = useBreadcrumbContext(); |
|
|
|
return portalNode |
|
? ReactDOM.createPortal( |
|
<Item {...props}> |
|
<ItemLink to={to}>{children}</ItemLink> |
|
</Item>, |
|
portalNode |
|
) |
|
: null; |
|
}; |
|
|
|
const Item = styled.li` |
|
display: inline; |
|
|
|
& + &::before { |
|
content: ""; |
|
display: inline-block; |
|
transform: rotate(15deg); |
|
border-right: 1px solid currentColor; |
|
height: 1em; |
|
margin: 0 8px -0.2em; |
|
} |
|
`; |
|
|
|
const ItemLink = styled(NavLink).attrs({ exact: true })` |
|
color: #36d; |
|
text-decoration: none; |
|
border-bottom: 1px solid transparent; |
|
|
|
&:hover { |
|
border-color: currentColor; |
|
} |
|
|
|
&.active { |
|
border: none; |
|
color: inherit; |
|
} |
|
`; |
|
|
|
export { BreadcrumbProvider, BreadcrumbPortal, Breadcrumb }; |