@lobehub/ui 5.14.2 → 5.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/es/Markdown/components/MarkdownTable/hastTableToMarkdown.mjs +82 -0
- package/es/Markdown/components/MarkdownTable/hastTableToMarkdown.mjs.map +1 -0
- package/es/Markdown/components/MarkdownTable/index.mjs +81 -0
- package/es/Markdown/components/MarkdownTable/index.mjs.map +1 -0
- package/es/hooks/useMarkdown/useMarkdownComponents.mjs +8 -1
- package/es/hooks/useMarkdown/useMarkdownComponents.mjs.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
//#region src/Markdown/components/MarkdownTable/hastTableToMarkdown.ts
|
|
2
|
+
const escapeCell = (text) => text.replaceAll("|", "\\|").replaceAll(/\r?\n/g, "<br>");
|
|
3
|
+
const matchAlign = (source) => {
|
|
4
|
+
if (source.includes("center")) return "center";
|
|
5
|
+
if (source.includes("right")) return "right";
|
|
6
|
+
if (source.includes("left")) return "left";
|
|
7
|
+
return null;
|
|
8
|
+
};
|
|
9
|
+
const readAlign = (node) => {
|
|
10
|
+
const style = node?.properties?.style;
|
|
11
|
+
const align = node?.properties?.align;
|
|
12
|
+
const styleStr = typeof style === "string" ? style.toLowerCase() : "";
|
|
13
|
+
const alignStr = typeof align === "string" ? align.toLowerCase() : "";
|
|
14
|
+
return matchAlign(styleStr) ?? matchAlign(alignStr);
|
|
15
|
+
};
|
|
16
|
+
const encodeInlineCode = (text) => {
|
|
17
|
+
let longestRun = 0;
|
|
18
|
+
const runs = text.match(/`+/g);
|
|
19
|
+
if (runs) for (const run of runs) longestRun = Math.max(longestRun, run.length);
|
|
20
|
+
const fence = "`".repeat(longestRun + 1);
|
|
21
|
+
return `${fence}${text.startsWith("`") || text.endsWith("`") ? ` ${text} ` : text}${fence}`;
|
|
22
|
+
};
|
|
23
|
+
const renderInline = (node) => {
|
|
24
|
+
if (node.type === "text") return node.value ?? "";
|
|
25
|
+
if (node.type !== "element") return "";
|
|
26
|
+
const inner = (node.children ?? []).map((child) => renderInline(child)).join("");
|
|
27
|
+
switch (node.tagName) {
|
|
28
|
+
case "br": return "<br>";
|
|
29
|
+
case "code": return encodeInlineCode(inner);
|
|
30
|
+
case "strong":
|
|
31
|
+
case "b": return `**${inner}**`;
|
|
32
|
+
case "em":
|
|
33
|
+
case "i": return `*${inner}*`;
|
|
34
|
+
case "del":
|
|
35
|
+
case "s": return `~~${inner}~~`;
|
|
36
|
+
case "a": {
|
|
37
|
+
const href = node.properties?.href;
|
|
38
|
+
return href ? `[${inner}](${href})` : inner;
|
|
39
|
+
}
|
|
40
|
+
case "img": {
|
|
41
|
+
const src = node.properties?.src ?? "";
|
|
42
|
+
return ``;
|
|
43
|
+
}
|
|
44
|
+
default: return inner;
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
const renderCell = (cell) => escapeCell(renderInline(cell)).trim();
|
|
48
|
+
const findChild = (node, tag) => node?.children?.find((child) => child.type === "element" && child.tagName === tag);
|
|
49
|
+
const findAllChildren = (node, tag) => (node?.children ?? []).filter((child) => child.type === "element" && child.tagName === tag);
|
|
50
|
+
const getRowCells = (row) => (row.children ?? []).filter((child) => child.type === "element" && (child.tagName === "th" || child.tagName === "td"));
|
|
51
|
+
const alignToDivider = (align) => {
|
|
52
|
+
switch (align) {
|
|
53
|
+
case "center": return ":---:";
|
|
54
|
+
case "left": return ":---";
|
|
55
|
+
case "right": return "---:";
|
|
56
|
+
default: return "---";
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
const hastTableToMarkdown = (node) => {
|
|
60
|
+
if (!node) return "";
|
|
61
|
+
const thead = findChild(node, "thead");
|
|
62
|
+
const tbody = findChild(node, "tbody");
|
|
63
|
+
const headerRow = findChild(thead, "tr");
|
|
64
|
+
const headerCells = headerRow ? getRowCells(headerRow) : [];
|
|
65
|
+
const bodyRows = findAllChildren(tbody, "tr");
|
|
66
|
+
const columnCount = Math.max(headerCells.length, ...bodyRows.map((row) => getRowCells(row).length));
|
|
67
|
+
if (columnCount === 0) return "";
|
|
68
|
+
const headerTexts = Array.from({ length: columnCount }, (_, i) => headerCells[i] ? renderCell(headerCells[i]) : "");
|
|
69
|
+
const aligns = Array.from({ length: columnCount }, (_, i) => readAlign(headerCells[i]));
|
|
70
|
+
return [
|
|
71
|
+
`| ${headerTexts.join(" | ")} |`,
|
|
72
|
+
`| ${aligns.map((a) => alignToDivider(a)).join(" | ")} |`,
|
|
73
|
+
...bodyRows.map((row) => {
|
|
74
|
+
const cells = getRowCells(row);
|
|
75
|
+
return `| ${Array.from({ length: columnCount }, (_, i) => cells[i] ? renderCell(cells[i]) : "").join(" | ")} |`;
|
|
76
|
+
})
|
|
77
|
+
].join("\n");
|
|
78
|
+
};
|
|
79
|
+
//#endregion
|
|
80
|
+
export { hastTableToMarkdown };
|
|
81
|
+
|
|
82
|
+
//# sourceMappingURL=hastTableToMarkdown.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hastTableToMarkdown.mjs","names":[],"sources":["../../../../src/Markdown/components/MarkdownTable/hastTableToMarkdown.ts"],"sourcesContent":["type HastNode = {\n children?: HastNode[];\n properties?: Record<string, any>;\n tagName?: string;\n type: string;\n value?: string;\n};\n\nconst escapeCell = (text: string) => text.replaceAll('|', '\\\\|').replaceAll(/\\r?\\n/g, '<br>');\n\nconst matchAlign = (source: string): 'center' | 'left' | 'right' | null => {\n if (source.includes('center')) return 'center';\n if (source.includes('right')) return 'right';\n if (source.includes('left')) return 'left';\n return null;\n};\n\nconst readAlign = (node: HastNode | undefined): 'center' | 'left' | 'right' | null => {\n const style = node?.properties?.style;\n const align = node?.properties?.align;\n const styleStr = typeof style === 'string' ? style.toLowerCase() : '';\n const alignStr = typeof align === 'string' ? align.toLowerCase() : '';\n // Prefer the inline style hint (more specific) but fall back to the\n // explicit `align` attribute when style has no alignment keyword —\n // otherwise an unrelated style like `color: red` would suppress\n // `align=\"right\"`.\n return matchAlign(styleStr) ?? matchAlign(alignStr);\n};\n\n// CommonMark code-span rule: open and close with N backticks where N is\n// longer than any run of consecutive backticks inside the content. If the\n// content starts or ends with a backtick, pad with a single space on each\n// side (the parser strips one space when both sides are padded).\nconst encodeInlineCode = (text: string): string => {\n let longestRun = 0;\n const runs = text.match(/`+/g);\n if (runs) for (const run of runs) longestRun = Math.max(longestRun, run.length);\n const fence = '`'.repeat(longestRun + 1);\n const needsPad = text.startsWith('`') || text.endsWith('`');\n const body = needsPad ? ` ${text} ` : text;\n return `${fence}${body}${fence}`;\n};\n\nconst renderInline = (node: HastNode): string => {\n if (node.type === 'text') return node.value ?? '';\n if (node.type !== 'element') return '';\n\n const inner = (node.children ?? []).map((child) => renderInline(child)).join('');\n\n switch (node.tagName) {\n case 'br': {\n return '<br>';\n }\n case 'code': {\n return encodeInlineCode(inner);\n }\n case 'strong':\n case 'b': {\n return `**${inner}**`;\n }\n case 'em':\n case 'i': {\n return `*${inner}*`;\n }\n case 'del':\n case 's': {\n return `~~${inner}~~`;\n }\n case 'a': {\n const href = node.properties?.href;\n return href ? `[${inner}](${href})` : inner;\n }\n case 'img': {\n const src = node.properties?.src ?? '';\n const alt = node.properties?.alt ?? '';\n return ``;\n }\n default: {\n return inner;\n }\n }\n};\n\nconst renderCell = (cell: HastNode): string => escapeCell(renderInline(cell)).trim();\n\nconst findChild = (node: HastNode | undefined, tag: string): HastNode | undefined =>\n node?.children?.find((child) => child.type === 'element' && child.tagName === tag);\n\nconst findAllChildren = (node: HastNode | undefined, tag: string): HastNode[] =>\n (node?.children ?? []).filter((child) => child.type === 'element' && child.tagName === tag);\n\nconst getRowCells = (row: HastNode): HastNode[] =>\n (row.children ?? []).filter(\n (child) => child.type === 'element' && (child.tagName === 'th' || child.tagName === 'td'),\n );\n\nconst alignToDivider = (align: 'center' | 'left' | 'right' | null): string => {\n switch (align) {\n case 'center': {\n return ':---:';\n }\n case 'left': {\n return ':---';\n }\n case 'right': {\n return '---:';\n }\n default: {\n return '---';\n }\n }\n};\n\nexport const hastTableToMarkdown = (node: HastNode | undefined): string => {\n if (!node) return '';\n\n const thead = findChild(node, 'thead');\n const tbody = findChild(node, 'tbody');\n\n const headerRow = findChild(thead, 'tr');\n const headerCells = headerRow ? getRowCells(headerRow) : [];\n\n const bodyRows = findAllChildren(tbody, 'tr');\n const columnCount = Math.max(\n headerCells.length,\n ...bodyRows.map((row) => getRowCells(row).length),\n );\n\n if (columnCount === 0) return '';\n\n const headerTexts = Array.from({ length: columnCount }, (_, i) =>\n headerCells[i] ? renderCell(headerCells[i]) : '',\n );\n\n const aligns = Array.from({ length: columnCount }, (_, i) => readAlign(headerCells[i]));\n\n const headerLine = `| ${headerTexts.join(' | ')} |`;\n const dividerLine = `| ${aligns.map((a) => alignToDivider(a)).join(' | ')} |`;\n const bodyLines = bodyRows.map((row) => {\n const cells = getRowCells(row);\n const texts = Array.from({ length: columnCount }, (_, i) =>\n cells[i] ? renderCell(cells[i]) : '',\n );\n return `| ${texts.join(' | ')} |`;\n });\n\n return [headerLine, dividerLine, ...bodyLines].join('\\n');\n};\n"],"mappings":"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"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import CopyButton from "../../../CopyButton/CopyButton.mjs";
|
|
3
|
+
import { hastTableToMarkdown } from "./hastTableToMarkdown.mjs";
|
|
4
|
+
import { memo, useCallback, useRef } from "react";
|
|
5
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
6
|
+
import { createStyles } from "antd-style";
|
|
7
|
+
//#region src/Markdown/components/MarkdownTable/index.tsx
|
|
8
|
+
const useStyles = createStyles(({ css, token }) => ({
|
|
9
|
+
copyButton: css`
|
|
10
|
+
position: absolute;
|
|
11
|
+
z-index: 1;
|
|
12
|
+
|
|
13
|
+
/* Vertical center of the header row = top padding (0.75em) + half of
|
|
14
|
+
the text line-box (line-height * 0.5em). Pulling the button up by
|
|
15
|
+
50% of its own height with transform parks it on that exact line. */
|
|
16
|
+
inset-block-start: calc(0.75em + (var(--lobe-markdown-line-height) * 0.5em));
|
|
17
|
+
inset-inline-end: 0.5em;
|
|
18
|
+
transform: translateY(-50%);
|
|
19
|
+
|
|
20
|
+
opacity: 0;
|
|
21
|
+
background: ${token.colorBgContainer};
|
|
22
|
+
box-shadow: 0 0 0 1px ${token.colorBorderSecondary};
|
|
23
|
+
|
|
24
|
+
transition: opacity ${token.motionDurationMid} ${token.motionEaseInOut};
|
|
25
|
+
`,
|
|
26
|
+
wrapper: css`
|
|
27
|
+
position: relative;
|
|
28
|
+
|
|
29
|
+
display: block;
|
|
30
|
+
|
|
31
|
+
width: max-content;
|
|
32
|
+
max-width: 100%;
|
|
33
|
+
margin-block: calc(var(--lobe-markdown-margin-multiple) * 0.5em);
|
|
34
|
+
|
|
35
|
+
&:hover .table-copy-button,
|
|
36
|
+
&:focus-within .table-copy-button {
|
|
37
|
+
opacity: 1;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/* Hand spacing to the wrapper so the absolutely-positioned copy
|
|
41
|
+
button anchors against the visible table edge instead of empty
|
|
42
|
+
margin space. */
|
|
43
|
+
> table {
|
|
44
|
+
margin-block: 0;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/* Reserve room for the copy button so right-aligned header text
|
|
48
|
+
doesn't slide under it. */
|
|
49
|
+
> table thead th:last-child {
|
|
50
|
+
padding-inline-end: calc(1em + 32px);
|
|
51
|
+
}
|
|
52
|
+
`
|
|
53
|
+
}));
|
|
54
|
+
const MarkdownTable = memo(({ node, children, ...rest }) => {
|
|
55
|
+
const { styles, cx } = useStyles();
|
|
56
|
+
const nodeRef = useRef(node);
|
|
57
|
+
nodeRef.current = node;
|
|
58
|
+
const getMarkdown = useCallback(() => hastTableToMarkdown(nodeRef.current), []);
|
|
59
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
60
|
+
className: styles.wrapper,
|
|
61
|
+
children: [/* @__PURE__ */ jsx(CopyButton, {
|
|
62
|
+
className: cx(styles.copyButton, "table-copy-button"),
|
|
63
|
+
content: getMarkdown,
|
|
64
|
+
glass: false,
|
|
65
|
+
size: {
|
|
66
|
+
blockSize: 24,
|
|
67
|
+
size: 14
|
|
68
|
+
},
|
|
69
|
+
title: "Copy table",
|
|
70
|
+
variant: "filled"
|
|
71
|
+
}), /* @__PURE__ */ jsx("table", {
|
|
72
|
+
...rest,
|
|
73
|
+
children
|
|
74
|
+
})]
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
MarkdownTable.displayName = "MarkdownTable";
|
|
78
|
+
//#endregion
|
|
79
|
+
export { MarkdownTable as default };
|
|
80
|
+
|
|
81
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../../../../src/Markdown/components/MarkdownTable/index.tsx"],"sourcesContent":["'use client';\n\nimport { createStyles } from 'antd-style';\nimport { memo, useCallback, useRef } from 'react';\n\nimport CopyButton from '@/CopyButton';\n\nimport { hastTableToMarkdown } from './hastTableToMarkdown';\n\nconst useStyles = createStyles(({ css, token }) => ({\n copyButton: css`\n position: absolute;\n z-index: 1;\n\n /* Vertical center of the header row = top padding (0.75em) + half of\n the text line-box (line-height * 0.5em). Pulling the button up by\n 50% of its own height with transform parks it on that exact line. */\n inset-block-start: calc(0.75em + (var(--lobe-markdown-line-height) * 0.5em));\n inset-inline-end: 0.5em;\n transform: translateY(-50%);\n\n opacity: 0;\n background: ${token.colorBgContainer};\n box-shadow: 0 0 0 1px ${token.colorBorderSecondary};\n\n transition: opacity ${token.motionDurationMid} ${token.motionEaseInOut};\n `,\n wrapper: css`\n position: relative;\n\n display: block;\n\n width: max-content;\n max-width: 100%;\n margin-block: calc(var(--lobe-markdown-margin-multiple) * 0.5em);\n\n &:hover .table-copy-button,\n &:focus-within .table-copy-button {\n opacity: 1;\n }\n\n /* Hand spacing to the wrapper so the absolutely-positioned copy\n button anchors against the visible table edge instead of empty\n margin space. */\n > table {\n margin-block: 0;\n }\n\n /* Reserve room for the copy button so right-aligned header text\n doesn't slide under it. */\n > table thead th:last-child {\n padding-inline-end: calc(1em + 32px);\n }\n `,\n}));\n\ninterface MarkdownTableProps {\n children?: React.ReactNode;\n node?: any;\n}\n\nconst MarkdownTable = memo<MarkdownTableProps>(({ node, children, ...rest }) => {\n const { styles, cx } = useStyles();\n const nodeRef = useRef(node);\n nodeRef.current = node;\n\n const getMarkdown = useCallback(() => hastTableToMarkdown(nodeRef.current), []);\n\n return (\n <div className={styles.wrapper}>\n <CopyButton\n className={cx(styles.copyButton, 'table-copy-button')}\n content={getMarkdown}\n glass={false}\n size={{ blockSize: 24, size: 14 }}\n title=\"Copy table\"\n variant=\"filled\"\n />\n <table {...rest}>{children}</table>\n </div>\n );\n});\n\nMarkdownTable.displayName = 'MarkdownTable';\n\nexport default MarkdownTable;\n"],"mappings":";;;;;;;AASA,MAAM,YAAY,cAAc,EAAE,KAAK,aAAa;CAClD,YAAY,GAAG;;;;;;;;;;;;kBAYC,MAAM,iBAAiB;4BACb,MAAM,qBAAqB;;0BAE7B,MAAM,kBAAkB,GAAG,MAAM,gBAAgB;;CAEzE,SAAS,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2Bb,EAAE;AAOH,MAAM,gBAAgB,MAA0B,EAAE,MAAM,UAAU,GAAG,WAAW;CAC9E,MAAM,EAAE,QAAQ,OAAO,WAAW;CAClC,MAAM,UAAU,OAAO,KAAK;AAC5B,SAAQ,UAAU;CAElB,MAAM,cAAc,kBAAkB,oBAAoB,QAAQ,QAAQ,EAAE,EAAE,CAAC;AAE/E,QACE,qBAAC,OAAD;EAAK,WAAW,OAAO;YAAvB,CACE,oBAAC,YAAD;GACE,WAAW,GAAG,OAAO,YAAY,oBAAoB;GACrD,SAAS;GACT,OAAO;GACP,MAAM;IAAE,WAAW;IAAI,MAAM;IAAI;GACjC,OAAM;GACN,SAAQ;GACR,CAAA,EACF,oBAAC,SAAD;GAAO,GAAI;GAAO;GAAiB,CAAA,CAC/B;;EAER;AAEF,cAAc,cAAc"}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import Hotkey from "../../Hotkey/Hotkey.mjs";
|
|
3
3
|
import { useMarkdownContext } from "../../Markdown/components/MarkdownProvider.mjs";
|
|
4
4
|
import { CodeBlock } from "../../Markdown/components/CodeBlock.mjs";
|
|
5
|
+
import MarkdownTable from "../../Markdown/components/MarkdownTable/index.mjs";
|
|
5
6
|
import Image from "../../mdx/mdxComponents/Image.mjs";
|
|
6
7
|
import Link from "../../mdx/mdxComponents/Link.mjs";
|
|
7
8
|
import Section from "../../mdx/mdxComponents/Section.mjs";
|
|
@@ -78,6 +79,10 @@ const useMarkdownComponents = () => {
|
|
|
78
79
|
componentProps?.pre
|
|
79
80
|
]);
|
|
80
81
|
const memoColorPreview = useCallback(({ node, ...props }) => /* @__PURE__ */ jsx("code", { ...props }), []);
|
|
82
|
+
const memoTable = useCallback(({ node, ...props }) => /* @__PURE__ */ jsx(MarkdownTable, {
|
|
83
|
+
node,
|
|
84
|
+
...props
|
|
85
|
+
}), []);
|
|
81
86
|
const memoComponents = useMemo(() => ({
|
|
82
87
|
a: memoA,
|
|
83
88
|
br: memoBr,
|
|
@@ -87,6 +92,7 @@ const useMarkdownComponents = () => {
|
|
|
87
92
|
p: memeP,
|
|
88
93
|
pre: memoPre,
|
|
89
94
|
section: memoSection,
|
|
95
|
+
table: memoTable,
|
|
90
96
|
video: memoVideo
|
|
91
97
|
}), [
|
|
92
98
|
memoA,
|
|
@@ -97,7 +103,8 @@ const useMarkdownComponents = () => {
|
|
|
97
103
|
memoSection,
|
|
98
104
|
memeP,
|
|
99
105
|
memoColorPreview,
|
|
100
|
-
memoKbd
|
|
106
|
+
memoKbd,
|
|
107
|
+
memoTable
|
|
101
108
|
]);
|
|
102
109
|
return useMemo(() => ({
|
|
103
110
|
...memoComponents,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useMarkdownComponents.mjs","names":[],"sources":["../../../src/hooks/useMarkdown/useMarkdownComponents.tsx"],"sourcesContent":["'use client';\n\nimport { useCallback, useMemo } from 'react';\nimport type { Components } from 'react-markdown';\n\nimport Hotkey from '@/Hotkey';\nimport { CodeBlock } from '@/Markdown/components/CodeBlock';\nimport { useMarkdownContext } from '@/Markdown/components/MarkdownProvider';\nimport Image from '@/mdx/mdxComponents/Image';\nimport Link from '@/mdx/mdxComponents/Link';\nimport Section from '@/mdx/mdxComponents/Section';\nimport Video from '@/mdx/mdxComponents/Video';\n\nexport const useMarkdownComponents = (): Components => {\n const {\n components,\n animated,\n citations,\n componentProps,\n enableHtmlPreview,\n enableMermaid,\n fullFeaturedCodeBlock,\n showFootnotes,\n } = useMarkdownContext();\n\n const memoA = useCallback(\n ({ node, ...props }: any) => <Link citations={citations} {...props} {...componentProps?.a} />,\n [citations, componentProps?.a],\n );\n\n const memoImg = useCallback(\n ({ node, ...props }: any) => <Image {...props} {...componentProps?.img} />,\n [componentProps?.img],\n );\n\n const memoVideo = useCallback(\n ({ node, ...props }: any) => <Video {...props} {...componentProps?.video} />,\n [componentProps?.video],\n );\n\n const memoSection = useCallback(\n ({ node, ...props }: any) => <Section showFootnotes={showFootnotes} {...props} />,\n [showFootnotes],\n );\n\n const memoKbd = useCallback(\n ({ children }: any) => <Hotkey keys={children} style={{ display: 'inline-flex' }} />,\n [],\n );\n\n const memoBr = useCallback(() => <br />, []);\n\n const memeP = useCallback(({ style, children, className }: any) => {\n const skipWrapperTags = ['img', 'video'];\n if (typeof children === 'object' && skipWrapperTags.includes(children?.props?.node?.tagName)) {\n return children;\n }\n return (\n <p className={className} style={style}>\n {children}\n </p>\n );\n }, []);\n\n // Stable references for theme objects to prevent unnecessary re-renders\n const highlightTheme = useMemo(\n () => componentProps?.highlight?.theme,\n [JSON.stringify(componentProps?.highlight?.theme)],\n );\n\n const mermaidTheme = useMemo(\n () => componentProps?.mermaid?.theme,\n [JSON.stringify(componentProps?.mermaid?.theme)],\n );\n\n // Create stable component props reference\n const stableComponentProps = useMemo(() => {\n if (!componentProps) return;\n\n return {\n highlight: componentProps.highlight\n ? { ...componentProps.highlight, theme: highlightTheme }\n : undefined,\n html: componentProps.html,\n mermaid: componentProps.mermaid\n ? { ...componentProps.mermaid, theme: mermaidTheme }\n : undefined,\n };\n }, [highlightTheme, mermaidTheme, componentProps?.html]);\n\n const memoPre = useCallback(\n ({ node, ...props }: any) => (\n <CodeBlock\n animated={animated}\n enableHtmlPreview={enableHtmlPreview}\n enableMermaid={enableMermaid}\n fullFeatured={fullFeaturedCodeBlock}\n {...stableComponentProps}\n {...componentProps?.pre}\n {...props}\n />\n ),\n [\n animated,\n enableHtmlPreview,\n enableMermaid,\n fullFeaturedCodeBlock,\n stableComponentProps,\n componentProps?.pre,\n ],\n );\n\n const memoColorPreview = useCallback(({ node, ...props }: any) => <code {...props} />, []);\n\n const memoComponents = useMemo(\n () => ({\n a: memoA,\n br: memoBr,\n colorPreview: memoColorPreview,\n img: memoImg,\n kbd: memoKbd,\n p: memeP,\n pre: memoPre,\n section: memoSection,\n video: memoVideo,\n }),\n [memoA
|
|
1
|
+
{"version":3,"file":"useMarkdownComponents.mjs","names":[],"sources":["../../../src/hooks/useMarkdown/useMarkdownComponents.tsx"],"sourcesContent":["'use client';\n\nimport { useCallback, useMemo } from 'react';\nimport type { Components } from 'react-markdown';\n\nimport Hotkey from '@/Hotkey';\nimport { CodeBlock } from '@/Markdown/components/CodeBlock';\nimport { useMarkdownContext } from '@/Markdown/components/MarkdownProvider';\nimport MarkdownTable from '@/Markdown/components/MarkdownTable';\nimport Image from '@/mdx/mdxComponents/Image';\nimport Link from '@/mdx/mdxComponents/Link';\nimport Section from '@/mdx/mdxComponents/Section';\nimport Video from '@/mdx/mdxComponents/Video';\n\nexport const useMarkdownComponents = (): Components => {\n const {\n components,\n animated,\n citations,\n componentProps,\n enableHtmlPreview,\n enableMermaid,\n fullFeaturedCodeBlock,\n showFootnotes,\n } = useMarkdownContext();\n\n const memoA = useCallback(\n ({ node, ...props }: any) => <Link citations={citations} {...props} {...componentProps?.a} />,\n [citations, componentProps?.a],\n );\n\n const memoImg = useCallback(\n ({ node, ...props }: any) => <Image {...props} {...componentProps?.img} />,\n [componentProps?.img],\n );\n\n const memoVideo = useCallback(\n ({ node, ...props }: any) => <Video {...props} {...componentProps?.video} />,\n [componentProps?.video],\n );\n\n const memoSection = useCallback(\n ({ node, ...props }: any) => <Section showFootnotes={showFootnotes} {...props} />,\n [showFootnotes],\n );\n\n const memoKbd = useCallback(\n ({ children }: any) => <Hotkey keys={children} style={{ display: 'inline-flex' }} />,\n [],\n );\n\n const memoBr = useCallback(() => <br />, []);\n\n const memeP = useCallback(({ style, children, className }: any) => {\n const skipWrapperTags = ['img', 'video'];\n if (typeof children === 'object' && skipWrapperTags.includes(children?.props?.node?.tagName)) {\n return children;\n }\n return (\n <p className={className} style={style}>\n {children}\n </p>\n );\n }, []);\n\n // Stable references for theme objects to prevent unnecessary re-renders\n const highlightTheme = useMemo(\n () => componentProps?.highlight?.theme,\n [JSON.stringify(componentProps?.highlight?.theme)],\n );\n\n const mermaidTheme = useMemo(\n () => componentProps?.mermaid?.theme,\n [JSON.stringify(componentProps?.mermaid?.theme)],\n );\n\n // Create stable component props reference\n const stableComponentProps = useMemo(() => {\n if (!componentProps) return;\n\n return {\n highlight: componentProps.highlight\n ? { ...componentProps.highlight, theme: highlightTheme }\n : undefined,\n html: componentProps.html,\n mermaid: componentProps.mermaid\n ? { ...componentProps.mermaid, theme: mermaidTheme }\n : undefined,\n };\n }, [highlightTheme, mermaidTheme, componentProps?.html]);\n\n const memoPre = useCallback(\n ({ node, ...props }: any) => (\n <CodeBlock\n animated={animated}\n enableHtmlPreview={enableHtmlPreview}\n enableMermaid={enableMermaid}\n fullFeatured={fullFeaturedCodeBlock}\n {...stableComponentProps}\n {...componentProps?.pre}\n {...props}\n />\n ),\n [\n animated,\n enableHtmlPreview,\n enableMermaid,\n fullFeaturedCodeBlock,\n stableComponentProps,\n componentProps?.pre,\n ],\n );\n\n const memoColorPreview = useCallback(({ node, ...props }: any) => <code {...props} />, []);\n\n const memoTable = useCallback(\n ({ node, ...props }: any) => <MarkdownTable node={node} {...props} />,\n [],\n );\n\n const memoComponents = useMemo(\n () => ({\n a: memoA,\n br: memoBr,\n colorPreview: memoColorPreview,\n img: memoImg,\n kbd: memoKbd,\n p: memeP,\n pre: memoPre,\n section: memoSection,\n table: memoTable,\n video: memoVideo,\n }),\n [\n memoA,\n memoBr,\n memoImg,\n memoVideo,\n memoPre,\n memoSection,\n memeP,\n memoColorPreview,\n memoKbd,\n memoTable,\n ],\n );\n\n return useMemo(\n () => ({\n ...memoComponents,\n ...components,\n }),\n [memoComponents, components],\n );\n};\n"],"mappings":";;;;;;;;;;;;AAcA,MAAa,8BAA0C;CACrD,MAAM,EACJ,YACA,UACA,WACA,gBACA,mBACA,eACA,uBACA,kBACE,oBAAoB;CAExB,MAAM,QAAQ,aACX,EAAE,MAAM,GAAG,YAAiB,oBAAC,MAAD;EAAiB;EAAW,GAAI;EAAO,GAAI,gBAAgB;EAAK,CAAA,EAC7F,CAAC,WAAW,gBAAgB,EAAE,CAC/B;CAED,MAAM,UAAU,aACb,EAAE,MAAM,GAAG,YAAiB,oBAAC,OAAD;EAAO,GAAI;EAAO,GAAI,gBAAgB;EAAO,CAAA,EAC1E,CAAC,gBAAgB,IAAI,CACtB;CAED,MAAM,YAAY,aACf,EAAE,MAAM,GAAG,YAAiB,oBAAC,OAAD;EAAO,GAAI;EAAO,GAAI,gBAAgB;EAAS,CAAA,EAC5E,CAAC,gBAAgB,MAAM,CACxB;CAED,MAAM,cAAc,aACjB,EAAE,MAAM,GAAG,YAAiB,oBAAC,SAAD;EAAwB;EAAe,GAAI;EAAS,CAAA,EACjF,CAAC,cAAc,CAChB;CAED,MAAM,UAAU,aACb,EAAE,eAAoB,oBAAC,QAAD;EAAQ,MAAM;EAAU,OAAO,EAAE,SAAS,eAAe;EAAI,CAAA,EACpF,EAAE,CACH;CAED,MAAM,SAAS,kBAAkB,oBAAC,MAAD,EAAM,CAAA,EAAE,EAAE,CAAC;CAE5C,MAAM,QAAQ,aAAa,EAAE,OAAO,UAAU,gBAAqB;AAEjE,MAAI,OAAO,aAAa,YAAY,CADX,OAAO,QACmB,CAAC,SAAS,UAAU,OAAO,MAAM,QAAQ,CAC1F,QAAO;AAET,SACE,oBAAC,KAAD;GAAc;GAAkB;GAC7B;GACC,CAAA;IAEL,EAAE,CAAC;CAGN,MAAM,iBAAiB,cACf,gBAAgB,WAAW,OACjC,CAAC,KAAK,UAAU,gBAAgB,WAAW,MAAM,CAAC,CACnD;CAED,MAAM,eAAe,cACb,gBAAgB,SAAS,OAC/B,CAAC,KAAK,UAAU,gBAAgB,SAAS,MAAM,CAAC,CACjD;CAGD,MAAM,uBAAuB,cAAc;AACzC,MAAI,CAAC,eAAgB;AAErB,SAAO;GACL,WAAW,eAAe,YACtB;IAAE,GAAG,eAAe;IAAW,OAAO;IAAgB,GACtD,KAAA;GACJ,MAAM,eAAe;GACrB,SAAS,eAAe,UACpB;IAAE,GAAG,eAAe;IAAS,OAAO;IAAc,GAClD,KAAA;GACL;IACA;EAAC;EAAgB;EAAc,gBAAgB;EAAK,CAAC;CAExD,MAAM,UAAU,aACb,EAAE,MAAM,GAAG,YACV,oBAAC,WAAD;EACY;EACS;EACJ;EACf,cAAc;EACd,GAAI;EACJ,GAAI,gBAAgB;EACpB,GAAI;EACJ,CAAA,EAEJ;EACE;EACA;EACA;EACA;EACA;EACA,gBAAgB;EACjB,CACF;CAED,MAAM,mBAAmB,aAAa,EAAE,MAAM,GAAG,YAAiB,oBAAC,QAAD,EAAM,GAAI,OAAS,CAAA,EAAE,EAAE,CAAC;CAE1F,MAAM,YAAY,aACf,EAAE,MAAM,GAAG,YAAiB,oBAAC,eAAD;EAAqB;EAAM,GAAI;EAAS,CAAA,EACrE,EAAE,CACH;CAED,MAAM,iBAAiB,eACd;EACL,GAAG;EACH,IAAI;EACJ,cAAc;EACd,KAAK;EACL,KAAK;EACL,GAAG;EACH,KAAK;EACL,SAAS;EACT,OAAO;EACP,OAAO;EACR,GACD;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACD,CACF;AAED,QAAO,eACE;EACL,GAAG;EACH,GAAG;EACJ,GACD,CAAC,gBAAgB,WAAW,CAC7B"}
|