packages/gatsby-components/src/rich-text-element/index.tsx
/* eslint-disable @typescript-eslint/no-explicit-any */
import React from 'react';
import parseHTML, { Element, domToReact } from 'html-react-parser';
import { ImageItem } from '../image-element';
const IMAGE_ID_ATTRIBUTE_IDENTIFIER = 'data-image-id';
const LINKED_ITEM_ID_ATTRIBUTE_IDENTIFIER = 'data-item-id';
interface Props {
value: string;
linkedItems?: any[];
resolveLinkedItem?: Function;
images?: ImageItem[];
resolveImage?: ((image?: ImageItem) => JSX.Element) | undefined;
links?: any[];
resolveLink?: Function;
resolveDomNode?: Function;
}
const isLinkedItem = (domNode: Element): boolean =>
domNode.name === 'object' &&
domNode.attribs?.type === 'application/kenticocloud';
const isImage = (domNode: Element): boolean =>
domNode.name === 'figure' &&
typeof domNode.attribs?.[IMAGE_ID_ATTRIBUTE_IDENTIFIER] !== 'undefined';
const isLink = (domNode: Element): boolean =>
domNode.name === 'a' &&
typeof domNode.attribs?.[LINKED_ITEM_ID_ATTRIBUTE_IDENTIFIER] !== 'undefined';
const replaceNode = (
domNode: Element,
linkedItems: any[] | undefined,
resolveLinkedItem: Function | undefined,
images: any[] | undefined,
resolveImage: ((image?: ImageItem) => JSX.Element) | undefined,
links: any[] | undefined,
resolveLink: Function | undefined,
resolveDomNode: Function | undefined,
): JSX.Element | void => {
if (resolveLinkedItem && linkedItems) {
if (isLinkedItem(domNode)) {
const codeName = domNode.attribs?.['data-codename'];
const linkedItem = linkedItems.find(
item => item?.system?.codename === codeName,
);
return resolveLinkedItem(linkedItem, domNode);
}
}
if (resolveImage && images) {
if (isImage(domNode)) {
const imageId = domNode.attribs?.[IMAGE_ID_ATTRIBUTE_IDENTIFIER];
const image = images.find(image => image?.image_id === imageId);
return resolveImage(image);
}
}
if (resolveLink && links) {
if (isLink(domNode)) {
const linkId = domNode.attribs?.[LINKED_ITEM_ID_ATTRIBUTE_IDENTIFIER];
const link = links.find(links => links?.link_id === linkId);
return resolveLink(link, domNode);
}
}
if (resolveDomNode) {
return resolveDomNode(domNode, domToReact);
}
};
const RichTextElement = ({
value,
linkedItems,
resolveLinkedItem,
images,
resolveImage,
links,
resolveLink,
resolveDomNode,
}: Props): JSX.Element => {
const result = parseHTML(value, {
replace: (domNode: Element) =>
replaceNode(
domNode,
linkedItems,
resolveLinkedItem,
images,
resolveImage,
links,
resolveLink,
resolveDomNode,
),
});
if (result as JSX.Element[]) {
return <>{result}</>;
}
return result as JSX.Element;
};
export { RichTextElement };