Created
May 21, 2024 19:31
-
-
Save tristanwagner/b7b3e3d433f8ffd1d6352208c9f047bb to your computer and use it in GitHub Desktop.
This file contains hidden or 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 {ComponentPropsWithoutRef, useEffect, useRef, useState} from "react" | |
import styled from "styled-components"; | |
import RecipientsBadge from "./RecipientsBadge"; | |
const RecipientsTooltip = styled.span` | |
position: fixed; | |
top: 8px; | |
right: 8px; | |
display: none; | |
align-items: center; | |
padding: 8px 16px; | |
border-radius: 24px; | |
background-color: #666; | |
color: #f0f0f0; | |
`; | |
export type RecipientDisplayProps = { | |
recipients: string[] | |
} & Omit<ComponentPropsWithoutRef<'span'>, 'style'>; | |
function RecipientsDisplay({recipients, ...rest}: RecipientDisplayProps) { | |
const [overflowed, setOverflowed] = useState<boolean>(false); | |
const [displayedRecipients, setDisplayedRecipients] = useState<string[]>(recipients); | |
const [hiddenRecipients, setHiddenRecipients] = useState<string[]>([]); | |
const displayTextRef = useRef<HTMLSpanElement | null>(null); | |
const tooltipRef = useRef<HTMLSpanElement | null>(null); | |
// check if current content of the container overflows the parent | |
const isOverflowed = (container: HTMLSpanElement | null) => { | |
const parent: HTMLTableCellElement | null | undefined = container?.closest("td"); | |
const parentCs = getComputedStyle(parent as Element); | |
const parentWidth = parseFloat(parentCs.width) - (parseFloat(parentCs.paddingRight) + parseFloat(parentCs.paddingLeft)); | |
if (container && parentWidth) { | |
return container.offsetWidth > parentWidth; | |
} | |
return false; | |
}; | |
// Handle check for text to fit or not and update accordingly | |
useEffect(() => { | |
setOverflowed(isOverflowed(displayTextRef.current)); | |
if (overflowed && displayedRecipients.length > 1) { | |
setHiddenRecipients([displayedRecipients.slice(-1)[0], ...hiddenRecipients]); | |
setDisplayedRecipients(displayedRecipients.slice(0, -1)); | |
} | |
if (overflowed && displayedRecipients.length == 1 && displayTextRef?.current) { | |
displayTextRef.current.style.overflow = "hidden"; | |
displayTextRef.current.style.textOverflow = "ellipsis"; | |
} | |
}, [overflowed, displayedRecipients]); | |
// on mount handle window resize by adding an event listener | |
useEffect(() => { | |
const handleResize = () => { | |
setOverflowed(isOverflowed(displayTextRef.current)); | |
} | |
window.addEventListener('resize', handleResize); | |
return () => { | |
window.removeEventListener('resize', handleResize); | |
}; | |
}, []); | |
return ( | |
<span {...rest}> | |
<span ref={displayTextRef}> | |
{`${displayedRecipients.join(", ")}${hiddenRecipients.length ? ", ..." : ""}`} | |
</span> | |
{hiddenRecipients.length ? | |
<RecipientsBadge | |
onMouseEnter={() => { | |
if (tooltipRef?.current) tooltipRef.current.style.display = "flex"; | |
}} | |
onMouseLeave={() => { | |
if (tooltipRef?.current) tooltipRef.current.style.display = "none"; | |
}} | |
numTruncated={hiddenRecipients.length}/> | |
: null | |
} | |
<RecipientsTooltip ref={tooltipRef}>{recipients.join(", ")}</RecipientsTooltip> | |
</span> | |
) | |
} | |
export default styled(RecipientsDisplay)` | |
display: flex; | |
justify-content: space-between; | |
align-items: center; | |
`; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment