1import { type ComponentPropsWithoutRef, type JSX } from "react";
2import { type Components as MemoComponents } from "rehype-react";
3import { type Components as ReactMarkdownComponents } from "react-markdown";
4import { type Components as StreamdownComponents } from "streamdown";
5
6type MarkdownProps<Tag extends keyof JSX.IntrinsicElements> = ComponentPropsWithoutRef<Tag> & {
7 node?: unknown;
8};
9
10function randomHighlightColor() {
11 return `hsl(${Math.floor(Math.random() * 360)} 95% 78%)`;
12}
13
14function omitNode<Props extends { node?: unknown }>(props: Props): Omit<Props, "node"> {
15 const { node, ...rest } = props;
16 void node;
17 return rest;
18}
19
20function MarkdownParagraph(props: MarkdownProps<"p">) {
21 return <p {...omitNode(props)} />;
22}
23
24function MarkdownH1(props: MarkdownProps<"h1">) {
25 return <h1 {...omitNode(props)} />;
26}
27
28function MarkdownH2(props: MarkdownProps<"h2">) {
29 return <h2 {...omitNode(props)} />;
30}
31
32function MarkdownH3(props: MarkdownProps<"h3">) {
33 return <h3 {...omitNode(props)} />;
34}
35
36function MarkdownH4(props: MarkdownProps<"h4">) {
37 return <h4 {...omitNode(props)} />;
38}
39
40function MarkdownH5(props: MarkdownProps<"h5">) {
41 return <h5 {...omitNode(props)} />;
42}
43
44function MarkdownH6(props: MarkdownProps<"h6">) {
45 return <h6 {...omitNode(props)} />;
46}
47
48function MarkdownUnorderedList(props: MarkdownProps<"ul">) {
49 return <ul {...omitNode(props)} />;
50}
51
52function MarkdownOrderedList(props: MarkdownProps<"ol">) {
53 return <ol {...omitNode(props)} />;
54}
55
56function MarkdownListItem(props: MarkdownProps<"li">) {
57 return <li {...omitNode(props)} />;
58}
59
60function MarkdownBlockquote(props: MarkdownProps<"blockquote">) {
61 return <blockquote {...omitNode(props)} />;
62}
63
64function MarkdownPre(props: MarkdownProps<"pre">) {
65 return <pre {...omitNode(props)} />;
66}
67
68function MarkdownCode(props: MarkdownProps<"code">) {
69 return <code {...omitNode(props)} />;
70}
71
72function MarkdownLink(props: MarkdownProps<"a">) {
73 return <a {...omitNode(props)} />;
74}
75
76function MarkdownStrong(props: MarkdownProps<"strong">) {
77 const { style, ...rest } = omitNode(props);
78 return <strong {...rest} style={{ ...style, backgroundColor: randomHighlightColor() }} />;
79}
80
81function MarkdownEmphasis(props: MarkdownProps<"em">) {
82 const { style, ...rest } = omitNode(props);
83 return <em {...rest} style={{ ...style, backgroundColor: randomHighlightColor() }} />;
84}
85
86function MarkdownDelete(props: MarkdownProps<"del">) {
87 return <del {...omitNode(props)} />;
88}
89
90function MarkdownHorizontalRule(props: MarkdownProps<"hr">) {
91 return <hr {...omitNode(props)} />;
92}
93
94function MarkdownTable(props: MarkdownProps<"table">) {
95 return <table {...omitNode(props)} />;
96}
97
98function MarkdownTableHead(props: MarkdownProps<"thead">) {
99 return <thead {...omitNode(props)} />;
100}
101
102function MarkdownTableBody(props: MarkdownProps<"tbody">) {
103 return <tbody {...omitNode(props)} />;
104}
105
106function MarkdownTableRow(props: MarkdownProps<"tr">) {
107 return <tr {...omitNode(props)} />;
108}
109
110function MarkdownTableHeader(props: MarkdownProps<"th">) {
111 return <th {...omitNode(props)} />;
112}
113
114function MarkdownTableCell(props: MarkdownProps<"td">) {
115 return <td {...omitNode(props)} />;
116}
117
118function MarkdownInput(props: MarkdownProps<"input">) {
119 return <input {...omitNode(props)} />;
120}
121
122export const components: Partial<MemoComponents> = {
123 a: MarkdownLink,
124 blockquote: MarkdownBlockquote,
125 code: MarkdownCode,
126 del: MarkdownDelete,
127 em: MarkdownEmphasis,
128 h1: MarkdownH1,
129 h2: MarkdownH2,
130 h3: MarkdownH3,
131 h4: MarkdownH4,
132 h5: MarkdownH5,
133 h6: MarkdownH6,
134 hr: MarkdownHorizontalRule,
135 input: MarkdownInput,
136 li: MarkdownListItem,
137 ol: MarkdownOrderedList,
138 p: MarkdownParagraph,
139 pre: MarkdownPre,
140 strong: MarkdownStrong,
141 table: MarkdownTable,
142 tbody: MarkdownTableBody,
143 td: MarkdownTableCell,
144 th: MarkdownTableHeader,
145 thead: MarkdownTableHead,
146 tr: MarkdownTableRow,
147 ul: MarkdownUnorderedList,
148};
149
150export const reactMarkdownComponents = components as ReactMarkdownComponents;
151export const streamdownComponents = components as StreamdownComponents;