This PR fixes issue https://github.com/twentyhq/twenty/issues/11865. The highlight heading logic in TOC was checking the heading text which could be the same for multiple headings. The ids for these headings were also just the heading texts, leading to conflict in ids too. Fix: - Appended index of the heading item from the list of headings to the id of the heading. This fixed conflicting ids. - Used these unique ids to toggle the highlight style. Behaviour after the fix: https://github.com/user-attachments/assets/ab3bc205-0b0e-451d-b9cb-4fa852263efc Edit: close #11865 --------- Co-authored-by: prastoin <paul@twenty.com>
48 lines
1.2 KiB
TypeScript
48 lines
1.2 KiB
TypeScript
import {
|
|
Children,
|
|
cloneElement,
|
|
isValidElement,
|
|
ReactElement,
|
|
ReactNode,
|
|
} from 'react';
|
|
|
|
export const wrapHeadingsWithAnchor = (children: ReactNode): ReactNode => {
|
|
const hasChildren = (
|
|
element: ReactElement,
|
|
): element is ReactElement<{ children: ReactNode }> => {
|
|
return element.props.children !== undefined;
|
|
};
|
|
const idCounts = new Map<string, number>();
|
|
|
|
return Children.map(children, (child) => {
|
|
if (
|
|
isValidElement(child) &&
|
|
typeof child.type === 'string' &&
|
|
['h1', 'h2', 'h3', 'h4'].includes(child.type)
|
|
) {
|
|
const baseId = child.props.children
|
|
.toString()
|
|
.replace(/\s+/g, '-')
|
|
.toLowerCase();
|
|
const idCount = idCounts.get(baseId) ?? 0;
|
|
|
|
const id = idCount === 0 ? baseId : `${baseId}-${idCount}`;
|
|
idCounts.set(baseId, idCount + 1);
|
|
|
|
return cloneElement(child as ReactElement<any>, {
|
|
id,
|
|
className: 'anchor',
|
|
children: <a href={`#${id}`}>{child.props.children}</a>,
|
|
});
|
|
}
|
|
|
|
if (isValidElement(child) && hasChildren(child)) {
|
|
return cloneElement(child, {
|
|
children: wrapHeadingsWithAnchor(child.props.children),
|
|
});
|
|
}
|
|
|
|
return child;
|
|
});
|
|
};
|