Perplexica/ui/components/Markdown/NodesRenderer.tsx

47 lines
1.6 KiB
TypeScript
Raw Normal View History

2024-07-10 16:17:23 +08:00
import { isEqual } from "@guanghechen/equal";
import { useStateValue } from "@guanghechen/react-viewmodel";
import type { Node } from "@yozora/ast";
import React from "react";
import type { INodeRenderer, INodeRendererMap } from "./context";
import { useNodeRendererContext } from "./context";
2024-07-10 16:34:28 +08:00
export interface INodesRendererProperties {
2024-07-10 16:17:23 +08:00
/**
* Ast nodes.
*/
nodes?: Node[];
}
2024-07-10 16:34:28 +08:00
export const NodesRenderer: React.FC<INodesRendererProperties> = properties => {
const { nodes } = properties;
2024-07-10 16:17:23 +08:00
const { viewmodel } = useNodeRendererContext();
const rendererMap: Readonly<INodeRendererMap> = useStateValue(viewmodel.rendererMap$);
if (!Array.isArray(nodes) || nodes.length <= 0) return <React.Fragment />;
return <NodesRendererInner nodes={nodes} rendererMap={rendererMap} />;
};
2024-07-10 16:34:28 +08:00
interface IProperties {
2024-07-10 16:17:23 +08:00
nodes: Node[];
rendererMap: Readonly<INodeRendererMap>;
}
2024-07-10 16:34:28 +08:00
class NodesRendererInner extends React.Component<IProperties> {
public override shouldComponentUpdate(nextProperties: Readonly<IProperties>): boolean {
const properties = this.props;
return !isEqual(properties.nodes, nextProperties.nodes) || properties.rendererMap !== nextProperties.rendererMap;
2024-07-10 16:17:23 +08:00
}
public override render(): React.ReactElement {
const { nodes, rendererMap } = this.props;
return (
<React.Fragment>
{nodes.map((node, index) => {
const key = `${node.type}-${index}`;
const Renderer: INodeRenderer = rendererMap[node.type] ?? rendererMap._fallback;
return <Renderer key={key} {...node} />;
})}
</React.Fragment>
);
}
}