Created
October 3, 2023 05:44
-
-
Save haxibami/92fcacf891bb1af4c3b476c52385a529 to your computer and use it in GitHub Desktop.
A rehype plugin to wrap images inserted by markdown image directive (`![alt](src)`), within Astro contents
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
import { visit } from "unist-util-visit"; | |
import { isMdxJsxAttribute, isMdxJsxFlowElement } from "./hast-util-node-is"; | |
import type { Root } from "hast"; | |
import type { Plugin } from "unified"; | |
interface RehypeAstroFigureOptions { | |
/** | |
* Class names to add to the figure element. | |
* @default ["astro-figure"] | |
* */ | |
figureClassName?: string[]; | |
/** | |
* Class names to add to the div element wrapping the astro-image. | |
* @default ["astro-image-container"] | |
* */ | |
imageContainerClassName?: string[]; | |
/** | |
* | |
* Class names to add to the figcaption element. | |
* @default ["astro-figure-caption"] | |
* */ | |
figCaptionClassName?: string[]; | |
} | |
/** | |
* A rehype plugin to wrap astro-image elements in a figure element with a figcaption. | |
* @param options - Options to customize the class names of the figure, div, and figcaption elements. | |
* @returns A rehype plugin. | |
*/ | |
const rehypeAstroFigure: Plugin<[RehypeAstroFigureOptions?], Root> = ( | |
options, | |
) => { | |
const { figureClassName, imageContainerClassName, figCaptionClassName } = { | |
figureClassName: ["astro-figure"], | |
imageContainerClassName: ["astro-image-container"], | |
figCaptionClassName: ["astro-figure-caption"], | |
...options, | |
}; | |
return (tree) => { | |
visit(tree, "element", (node, index, parent) => { | |
if ( | |
node.tagName !== "p" || | |
!parent || | |
typeof index !== "number" || | |
node.children.length !== 1 || | |
!node.children[0] || | |
!isMdxJsxFlowElement(node.children[0]) | |
) { | |
return; | |
} | |
const child = node.children[0]; | |
if ( | |
!Object.hasOwn(child, "name") || | |
!Object.hasOwn(child, "attributes") || | |
child.type !== "mdxJsxFlowElement" || | |
child.name !== "astro-image" | |
) { | |
return; | |
} | |
const alt = child.attributes | |
.find((attr) => isMdxJsxAttribute(attr) && attr.name === "alt") | |
?.value?.toString(); | |
if (!alt) { | |
return; | |
} | |
parent.children[index] = { | |
type: "element", | |
tagName: "figure", | |
properties: { | |
className: figureClassName, | |
}, | |
children: [ | |
{ | |
type: "element", | |
tagName: "div", | |
properties: { | |
className: imageContainerClassName, | |
}, | |
children: [child], | |
}, | |
{ | |
type: "element", | |
tagName: "figcaption", | |
properties: { | |
className: figCaptionClassName, | |
}, | |
children: [ | |
{ | |
type: "text", | |
value: alt, | |
}, | |
], | |
}, | |
], | |
}; | |
}); | |
}; | |
}; | |
export default rehypeAstroFigure; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment