diff --git a/package.json b/package.json index 05780f0e4..baa25c0eb 100644 --- a/package.json +++ b/package.json @@ -43,6 +43,7 @@ "query-string": "^7.1.1", "react-instantsearch-hooks-web": "^6.38.1", "react-mailchimp-subscribe": "^2.1.3", + "rehype-format": "^5.0.0", "rehype-katex": "^7.0.0", "rehype-mermaidjs": "^1.0.1", "remark-gfm": "^4.0.0", diff --git a/src/components/Steps/Steps.astro b/src/components/Steps/Steps.astro new file mode 100644 index 000000000..907fddc42 --- /dev/null +++ b/src/components/Steps/Steps.astro @@ -0,0 +1,91 @@ +--- +import { processSteps } from "./rehype-steps" + +const content = await Astro.slots.render("default") +const { html } = processSteps(content) +--- + + + + diff --git a/src/components/Steps/rehype-steps.ts b/src/components/Steps/rehype-steps.ts new file mode 100644 index 000000000..9e4ade24d --- /dev/null +++ b/src/components/Steps/rehype-steps.ts @@ -0,0 +1,44 @@ +import type { Element, Root } from "hast" +import { rehype } from "rehype" +import rehypeFormat from "rehype-format" +import type { VFile } from "vfile" + +const prettyPrintProcessor = rehype().data("settings", { fragment: true }).use(rehypeFormat) +const prettyPrintHtml = (html: string) => prettyPrintProcessor.processSync({ value: html }).toString() + +const stepsProcessor = rehype() + .data("settings", { fragment: true }) + .use(function steps() { + return (tree: Root, vfile: VFile) => { + const rootElements = tree.children.filter((item): item is Element => item.type === "element") + const [rootElement] = rootElements + + // Ensure `role="list"` is set on the ordered list. + // We use `list-style: none` in the styles for this component and need to ensure the list + // retains its semantics in Safari, which will remove them otherwise. + rootElement.properties.role = "list" + // Add the required CSS class name, preserving existing classes if present. + if (!Array.isArray(rootElement.properties.className)) { + rootElement.properties.className = ["sl-steps"] + } else { + rootElement.properties.className.push("sl-steps") + } + + // Add the `start` attribute as a CSS custom property so we can use it as the starting index + // of the steps custom counter. + if (typeof rootElement.properties.start === "number") { + const styles = [`--sl-steps-start: ${rootElement.properties.start - 1}`] + if (rootElement.properties.style) styles.push(String(rootElement.properties.style)) + rootElement.properties.style = styles.join(";") + } + } + }) + +/** + * Process steps children: validates the HTML and adds `role="list"` to the ordered list. + * @param html Inner HTML passed to the `` component. + */ +export const processSteps = (html: string | undefined) => { + const file = stepsProcessor.processSync({ value: html }) + return { html: file.toString() } +} diff --git a/src/content/docs/en/article-components.mdx b/src/content/docs/en/article-components.mdx index 29c813eb5..0905d63da 100644 --- a/src/content/docs/en/article-components.mdx +++ b/src/content/docs/en/article-components.mdx @@ -15,6 +15,7 @@ import Aside from "../../../components/Aside.astro" import MarkmapView from "../../../components/MarkmapView/index.astro" import RPCTable from "../../../components/RPCTable/RPCTable.astro" import { Tabs, TabsContent } from "../../../components/Tabs" +import Steps from '../../../components/Steps/Steps.astro'; This is body text right under the article title. It typically is just paragraph text that's pretty straightforward. Then there's **bold text**, and _italic text_, and **_bold-italic text_**, and `inline-code` and **`bold inline code`** and even _`italic inline code`_ and **_`bold italic inline code`_**. And of course don't forget [links](#), and [**bold links**](#), and [_italic links_](#), and [**_bold-italic links_**](#). @@ -38,6 +39,21 @@ What else do we have? ##### H5 Heading +### Steps + + + + +1. Import the component into your MDX file: + + ```js + import { Steps } from '@astrojs/starlight/components'; + ``` + +2. Wrap `` around your ordered list items. + + + Let's see a horizontal rule. ---