Astro rich text renderer

For Astro, there is a helper library that makes the integration process of rich texts very simple.

To install, use npm or another package manager:

npm install @caisy/rich-text-astro-renderer --save

For ease of use, just pass the JSON and the component will convert it to HTML:

---
import RichTextRenderer from '@caisy/rich-text-astro-renderer';
...

---
<RichTextRenderer node={blogArticle.text.json} />

To ensure that you pass the correct object, it should contain something like this:

{ type: "doc", ... }

An basic example using the rich text render with Astro can also be found here on Stackblitz:
https://stackblitz.com/github/caisy-io/caisy-example-astro

Advanced: Document Linking

More advanced use case is for example to support linked assets or documents.
Therefor you need to fetch the connections and the json from the graphql API.
So the RichTextRenderer might look like this

<RichTextRenderer
  node={post.text.json}
  connections={post?.text?.connections}
  overwrites={{ documentLink: DocumentLink }}
/>

Where your DocumentLink and Asset component would look like this, to render a linked Asset:

src/components/DocumentLink.astro
---
import Asset from "./Asset.astro";
const { connections, node } = Astro.props;
---
{
  connections &&
    connections.map((component) => {
      if (
        component?.__typename === "Asset" &&
        node?.attrs?.documentId === component.id
      ) {
        return (
          <Asset {...component} />
        );
      }
      return null;
    })
}
<slot />
src/components/Asset.astro
---
import { Image } from "astro:assets";
const { src, description, width, height } = Astro.props;
---

{
  src && (
    <Image width={width} height={height} src={src} alt={description} />
  )
}

In case you linked an Asset you will always get __typename Asset - if the user can link other blueprints, you can expert there APIName here as __typename and check by for them. Remember you can pick the right connection, by matching the id from the connection to the documentId in the rich-text. The example above is using a graphql query partly like this:

text {
  json
  connections {
    __typename
    ... on Asset {
      src
      height
      width
      id
      description
    }
  }
}

For this sample with the images linked you can also find a stackblitz here.

Advanced: Code Blocks with Syntax Highlighting

To customize the rendering of code blocks and add syntax highlighting, you can use the overwrites prop of the RichTextRenderer component.
Here's an example:

CustomCodeBlock.astro
---
import { Code } from "astro:components";
import type { BuiltinLanguage, BundledTheme } from "shiki";

const { node } = Astro.props;

const codeBlockProps = {
    theme: "material-theme-palenight" as BundledTheme,
    code: node.content[0].text as string,
    lang: node.attrs.language as BuiltinLanguage,
    wrap: true,
};
---

<Code {...codeBlockProps}  />

In this example, we define a CustomCodeBlock component that receives the code block node as a prop. Inside the component, we extract the relevant properties such as the code content, language, and theme. We then pass these props to Astro's built-in Code component, which handles the syntax highlighting.

RichText.astro
---
import RichTextRenderer from "@caisy/rich-text-astro-renderer";
import CustomCodeBlock from "./CustomCodeBlock.astro";

const { node } = Astro.props;

const overwrites = {
    codeBlock: CustomCodeBlock,
};
---

<RichTextRenderer node={node} overwrites={overwrites} />

By providing the overwrites prop to the RichTextRenderer, we specify that code blocks should be rendered using our custom CustomCodeBlock component instead of the default rendering.

This approach allows you to customize the appearance and behavior of code blocks within your rich text content while leveraging Astro's built-in syntax highlighting capabilities.