Skip to content

Instantly share code, notes, and snippets.

@jrnxf
Created March 25, 2022 07:52
Show Gist options
  • Save jrnxf/f597df27ffbac5f4543101a8f7de9844 to your computer and use it in GitHub Desktop.
Save jrnxf/f597df27ffbac5f4543101a8f7de9844 to your computer and use it in GitHub Desktop.
RowLimitTags.tsx
import { Box } from "@mantine/core";
import { useCallback, useEffect, useRef, useState } from "react";
const tags = [
"Singing",
"Music Production",
"Piano",
"Baking",
"Art",
"Dancing",
"Engineering",
"Shoe Design",
"Knitting",
"Biking",
"Welding",
"Carpentry",
"Tattoo Design",
];
export default () => (
<RowLimitTags initialTags={tags} maxRows={2} paddingX={30} margin={20} />
);
type Props = {
initialTags: string[];
maxRows: number;
paddingX: number;
margin: number;
};
const RowLimitTags = ({ initialTags, maxRows, paddingX, margin }: Props) => {
const boundingRef = useRef<HTMLDivElement>(null);
const textWidthRef = useRef<HTMLSpanElement>(null);
const [displayedTags, setDisplayedTags] = useState<string[]>([]);
const calculate = useCallback(
(tags, maxRows, boundingWidth, tagsCut) => {
if (!boundingRef?.current || !textWidthRef?.current) return;
let rows: string[][] = [];
let currentRow: string[] = [];
let currentSumWidth = 0;
let iterTags;
if (tagsCut.length > 0) {
iterTags = [
...tags.slice(0, tags.length - tagsCut.length),
`+ ${tagsCut.length}`,
];
} else {
iterTags = tags;
}
for (const [idx, t] of iterTags.entries()) {
let elem = textWidthRef.current;
elem.innerText = t;
const currentTagWidth =
elem.getBoundingClientRect().width + paddingX * 2 + margin * 2;
if (currentSumWidth + currentTagWidth < boundingWidth) {
// the current tag can fit on this row
currentRow.push(t);
currentSumWidth += currentTagWidth;
} else {
// we need to start a new row
rows.push(currentRow);
if (rows.length == maxRows) {
let excessTags;
if (tagsCut.length > 0) {
iterTags.pop(); // get rid of the +n tag
excessTags = [iterTags.pop(), ...tagsCut];
} else {
excessTags = iterTags.slice(idx);
}
calculate(tags, maxRows, boundingWidth, excessTags);
return;
}
currentRow = [t];
currentSumWidth = currentTagWidth;
}
}
rows.push(currentRow);
// set displayed tags in here once you've recursed and hit break
setDisplayedTags(rows.flat());
},
[margin, paddingX]
);
const initCalculation = useCallback(() => {
if (boundingRef?.current && textWidthRef?.current) {
calculate(
initialTags,
maxRows,
boundingRef.current.getBoundingClientRect().width,
[]
);
}
}, [calculate, maxRows, initialTags]);
useEffect(() => {
initCalculation();
window.addEventListener("resize", initCalculation);
return () => {
window.removeEventListener("resize", initCalculation);
};
}, [initCalculation]);
return (
<>
<span ref={textWidthRef} style={{ fontSize: 40, visibility: "hidden" }} />
<Box
ref={boundingRef}
sx={(theme) => ({
background: theme.colors.gray[9],
display: "flex",
flexWrap: "wrap",
})}
>
{displayedTags?.map((tag, idx) => (
<Box
key={idx}
sx={(theme) => ({
background: theme.colors.gray[8],
fontSize: 40,
margin: `${margin}px`,
padding: `2px ${paddingX}px`,
borderRadius: 100,
})}
>
{tag}
</Box>
))}
</Box>
</>
);
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment