-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix: download component in the mdx (#2195)
- Loading branch information
1 parent
3f4f28e
commit f3b6571
Showing
15 changed files
with
282 additions
and
35 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
import type { Root as HastRoot } from "hast"; | ||
import { toMdast } from "hast-util-to-mdast"; | ||
import { mdastToMarkdown } from "../mdast-utils/mdast-to-markdown"; | ||
|
||
export function hastToMarkdown( | ||
hast: HastRoot, | ||
format: "mdx" | "md" = "mdx" | ||
): string { | ||
const mdast = toMdast(hast, { | ||
nodeHandlers: | ||
format === "mdx" | ||
? { | ||
// pass through node types | ||
mdxFlowExpression: (_state, node) => node, | ||
mdxJsxFlowElement: (_state, node) => node, | ||
mdxJsxTextElement: (_state, node) => node, | ||
mdxTextExpression: (_state, node) => node, | ||
mdxjsEsm: (_state, node) => node, | ||
} | ||
: undefined, | ||
}); | ||
if (mdast.type !== "root") { | ||
throw new Error("Expected root node"); | ||
} | ||
return mdastToMarkdown(mdast, format); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
12 changes: 10 additions & 2 deletions
12
packages/fern-docs/mdx/src/mdast-utils/mdast-to-markdown.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,11 +1,19 @@ | ||
import { compact } from "es-toolkit"; | ||
import type { Root as MdastRoot } from "mdast"; | ||
import { gfmToMarkdown } from "mdast-util-gfm"; | ||
import { mathToMarkdown } from "mdast-util-math"; | ||
import { mdxToMarkdown } from "mdast-util-mdx"; | ||
import { toMarkdown } from "mdast-util-to-markdown"; | ||
|
||
export function mdastToMarkdown(mdast: MdastRoot): string { | ||
export function mdastToMarkdown( | ||
mdast: MdastRoot, | ||
format: "mdx" | "md" = "mdx" | ||
): string { | ||
return toMarkdown(mdast, { | ||
extensions: [mdxToMarkdown(), mathToMarkdown(), gfmToMarkdown()], | ||
extensions: compact([ | ||
format === "mdx" ? mdxToMarkdown() : undefined, | ||
mathToMarkdown(), | ||
gfmToMarkdown(), | ||
]), | ||
}); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
17 changes: 17 additions & 0 deletions
17
packages/fern-docs/ui/src/mdx/components/download/Download.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
import { PropsWithChildren } from "react"; | ||
|
||
export function Download({ | ||
children, | ||
src, | ||
filename, | ||
}: PropsWithChildren<{ src?: string; filename?: string }>) { | ||
if (!src) { | ||
return children; | ||
} | ||
|
||
return ( | ||
<a href={src} download={filename || true}> | ||
{children} | ||
</a> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export * from "./Download"; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
58 changes: 58 additions & 0 deletions
58
packages/fern-docs/ui/src/mdx/plugins/rehype-download.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
import { hastToMarkdown, toTree } from "@fern-docs/mdx"; | ||
import { rehypeDownload } from "./rehype-download"; | ||
|
||
const run = rehypeDownload(); | ||
|
||
describe("rehypeDownload", () => { | ||
it("should be a noop if src is not set", () => { | ||
const ast = toTree(`<Download><Button /></Download>`).hast; | ||
run(ast); | ||
expect(hastToMarkdown(ast)).toMatchInlineSnapshot( | ||
` | ||
"<Download> | ||
<Button /> | ||
</Download> | ||
" | ||
` | ||
); | ||
}); | ||
|
||
it("should convert <Download> elements into <Button> elements with the `href` and `download` attributes set", () => { | ||
const ast = toTree( | ||
`<Download src="https://example.com/file.txt"><Button>Download me</Button></Download>` | ||
).hast; | ||
run(ast); | ||
expect(hastToMarkdown(ast)).toMatchInlineSnapshot( | ||
` | ||
"<Button href="https://example.com/file.txt" download>Download me</Button> | ||
" | ||
` | ||
); | ||
}); | ||
|
||
it("should include the filename in the `download` attribute", () => { | ||
const ast = toTree( | ||
`<Download src="https://example.com/file.txt" filename="my-file"><Button>Download me</Button></Download>` | ||
).hast; | ||
run(ast); | ||
expect(hastToMarkdown(ast)).toMatchInlineSnapshot( | ||
` | ||
"<Button href="https://example.com/file.txt" download="my-file">Download me</Button> | ||
" | ||
` | ||
); | ||
}); | ||
|
||
it("should be a noop if the child is not a <Button>", () => { | ||
const ast = toTree( | ||
`<Download src="https://example.com/file.txt"><strong>Download me</strong></Download>` | ||
).hast; | ||
run(ast); | ||
expect(hastToMarkdown(ast)).toMatchInlineSnapshot(` | ||
"<Download src="https://example.com/file.txt"> | ||
<strong>Download me</strong> | ||
</Download> | ||
" | ||
`); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
import { | ||
CONTINUE, | ||
Hast, | ||
isMdxJsxAttribute, | ||
isMdxJsxElementHast, | ||
SKIP, | ||
visit, | ||
} from "@fern-docs/mdx"; | ||
|
||
/** | ||
* The goal of this plugin is to squeeze the <Download> element into a <Button> element with the `href` and `download` attributes set. | ||
* This is to avoid <a><button /></a> which is invalid HTML. | ||
*/ | ||
export function rehypeDownload() { | ||
return (ast: Hast.Root) => { | ||
visit(ast, (node, index, parent) => { | ||
if (!isMdxJsxElementHast(node) || !parent || index == null) { | ||
return CONTINUE; | ||
} | ||
|
||
if ( | ||
node.name === "Download" && | ||
node.children.length === 1 && | ||
node.children[0] | ||
) { | ||
const child = node.children[0]; | ||
if (isMdxJsxElementHast(child) && child.name === "Button") { | ||
const srcAttr = node.attributes | ||
.filter(isMdxJsxAttribute) | ||
.find((attr) => attr.name === "src"); | ||
|
||
if (!srcAttr) { | ||
return CONTINUE; | ||
} | ||
|
||
const filenameAttr = node.attributes | ||
.filter(isMdxJsxAttribute) | ||
.find((attr) => attr.name === "filename"); | ||
|
||
// inject the src attribute as a href | ||
child.attributes.push({ | ||
type: "mdxJsxAttribute", | ||
name: "href", | ||
value: srcAttr.value, | ||
}); | ||
|
||
// force the button to be a download | ||
child.attributes.push({ | ||
type: "mdxJsxAttribute", | ||
name: "download", | ||
value: filenameAttr?.value, | ||
}); | ||
|
||
parent.children[index] = child; | ||
|
||
return SKIP; | ||
} | ||
} | ||
return CONTINUE; | ||
}); | ||
}; | ||
} |
Oops, something went wrong.