Skip to content

Commit

Permalink
feat: add nodes/marks passing to resolveFn, update demo and README (#168
Browse files Browse the repository at this point in the history
)

Signed-off-by: Edvinas Jurele <[email protected]>
Co-authored-by: Edoardo Sandon <[email protected]>
  • Loading branch information
edvinasjurele and Edo-San authored Mar 12, 2024
1 parent 1c6e9b3 commit bb07726
Show file tree
Hide file tree
Showing 7 changed files with 161 additions and 95 deletions.
63 changes: 53 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -148,39 +148,82 @@ Use `resolver` to enable and control the rendering of embedded components, and `
/>
```

### Content via prop

By default, content in `nodes` is handled automatically and passed via slots keeping configuration as follows:

```js
heading: ({ attrs: { level } }) => ({
component: Text,
props: { variant: `h${level}` },
}),
```
This implies that implementation of `Text` is as simple as:
```js
---
const { variant } = Astro.props;
const Component = variant || "p";
---

<Component>
<slot />
</Component>
```
However in some cases, the users do implementation via props only, thus without slots:
```js
---
const { variant, text } = Astro.props;
const Component = variant || "p";
---

<Component>
{text}
</Component>
```
This way the content must be handled explictly in the resolver function and passed via prop:
```js
heading: ({ attrs: { level }, content }) => ({
component: Text,
props: {
variant: `h${level}`,
text: content?.[0].text,
},
}),
```
## Schema
The schema has `nodes` and `marks` to be configurable:
```js
schema={{
nodes: {
heading: ({ attrs }) => ({ ... }),
heading: (node) => ({ ... }),
paragraph: () => ({ ... }),
text: () => ({ ... }),
hard_break: () => ({ ... }),
bullet_list: () => ({ ... }),
ordered_list: ({ attrs }) => ({ ... }),
ordered_list: (node) => ({ ... }),
list_item: () => ({ ... }),
horizontal_rule: () => ({ ... }),
blockquote: () => ({ ... }),
image: ({ attrs }) => ({ ... }),
code_block: ({ attrs }) => ({ ... }),
emoji: ({ attrs }) => ({ ... }),
image: (node) => ({ ... }),
code_block: (node) => ({ ... }),
emoji: (node) => ({ ... }),
},
marks: {
link: ({ attrs }) => { ... },
link: (mark) => { ... },
bold: () => ({ ... }),
underline: () => ({ ... }),
italic: () => ({ ... }),
styled: ({ attrs }) => { ... },
styled: (mark) => { ... },
strike: () => ({ ... }),
superscript: () => ({ ... }),
subscript: () => ({ ... }),
code: () => ({ ... }),
anchor: ({ attrs }) => ({ ... }),
textStyle: ({ attrs }) => ({ ... }),
highlight: ({ attrs }) => ({ ... }),
anchor: (mark) => ({ ... }),
textStyle: (mark) => ({ ... }),
highlight: (mark) => ({ ... }),
};
}}
```
Expand Down
36 changes: 0 additions & 36 deletions demo/src/components/CodeBlock.astro

This file was deleted.

14 changes: 14 additions & 0 deletions demo/src/components/Heading.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
---
type HeadingTag = "h1" | "h2" | "h3" | "h4" | "h5" | "h6";
export type Props = {
as: HeadingTag;
text: string;
};
const { as: Element = "h1", text, ...props } = Astro.props;
---

<Element id={props.id} {...props}>
{text}
</Element>
27 changes: 17 additions & 10 deletions demo/src/storyblok/RichText.astro
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
---
import RichTextRenderer, {
type RichTextType,
} from "storyblok-rich-text-astro-renderer/RichTextRenderer.astro";
import { type RichTextType } from "storyblok-rich-text-astro-renderer";
import RichTextRenderer from "storyblok-rich-text-astro-renderer/RichTextRenderer.astro";
import { storyblokEditable } from "@storyblok/astro";
import Link from "../components/Link.astro";
import StoryblokComponent from "@storyblok/astro/StoryblokComponent.astro";
import Text from "../components/Text.astro";
import BulletList from "../components/BulletList.astro";
import Blockquote from "../components/Blockquote.astro";
import Picture from "../components/Picture.astro";
import CodeBlock from "../components/CodeBlock.astro";
import InlineCode from "../components/InlineCode.astro";
import Styled from "../components/Styled.astro";
import Heading from "../components/Heading.astro";
import { Code } from "astro:components";
export interface Props {
blok: {
Expand All @@ -27,9 +27,12 @@ const { text } = blok;
content={text}
schema={{
nodes: {
heading: ({ attrs: { level } }) => ({
component: Text,
props: { variant: `h${level}` },
heading: ({ attrs: { level }, content }) => ({
component: Heading,
props: {
as: `h${level}`,
text: content?.[0].text,
},
}),
paragraph: () => ({
component: Text,
Expand Down Expand Up @@ -62,9 +65,13 @@ const { text } = blok;
component: Picture,
props: attrs,
}),
code_block: ({ attrs }) => ({
component: CodeBlock,
props: { syntax: attrs.class?.split("-")[1] },
code_block: ({ attrs, content }) => ({
component: Code, // native Astro Code component
props: {
lang: attrs.class?.split("-")[1],
theme: "solarized-dark",
code: content?.[0].text,
},
}),
},
marks: {
Expand Down
36 changes: 18 additions & 18 deletions lib/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,37 +8,37 @@ export type ComponentNode = {
content?: string | ComponentNode[];
};

type ResolverAttrs<Attrs> = ({ attrs }: { attrs: Attrs }) => ComponentNode;
type Resolver<Node> = (node: Node) => ComponentNode;
type Resolver = () => ComponentNode;

export type Schema = {
nodes?: {
heading?: ResolverAttrs<Heading["attrs"]>;
paragraph?: Resolver;
text?: Resolver;
hard_break?: Resolver;
bullet_list?: Resolver;
ordered_list?: ResolverAttrs<OrderedList["attrs"]>;
list_item?: Resolver;
horizontal_rule?: Resolver;
blockquote?: Resolver;
image?: ResolverAttrs<Image["attrs"]>;
code_block?: ResolverAttrs<CodeBlock["attrs"]>;
emoji?: ResolverAttrs<Emoji["attrs"]>;
heading?: Resolver<Heading>;
paragraph?: Resolver<Paragraph>;
text?: Resolver<Text>;
hard_break?: Resolver<Break>;
bullet_list?: Resolver<BulletList>;
ordered_list?: Resolver<OrderedList>;
list_item?: Resolver<ListItem>;
horizontal_rule?: Resolver<HorizontalRule>;
blockquote?: Resolver<Blockquote>;
image?: Resolver<Image>;
code_block?: Resolver<CodeBlock>;
emoji?: Resolver<Emoji>;
};
marks?: {
link?: ResolverAttrs<Link["attrs"]>;
link?: Resolver<Link>;
bold?: Resolver;
underline?: Resolver;
italic?: Resolver;
styled?: ResolverAttrs<Styled["attrs"]>;
styled?: Resolver<Styled>;
strike?: Resolver;
superscript?: Resolver;
subscript?: Resolver;
code?: Resolver;
anchor?: ResolverAttrs<Anchor["attrs"]>;
textStyle?: ResolverAttrs<TextStyle["attrs"]>;
highlight?: ResolverAttrs<Highlight["attrs"]>;
anchor?: Resolver<Anchor>;
textStyle?: Resolver<TextStyle>;
highlight?: Resolver<Highlight>;
};
};

Expand Down
24 changes: 24 additions & 0 deletions lib/src/utils/resolveRichTextToNodes.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,30 @@ describe("resolveNode", () => {
content: [{ content: "Hello from rich text" }],
});

// with schema override - content via prop
expect(
resolveNode(node, {
schema: {
nodes: {
heading: ({ attrs: { level }, content }) => ({
component: Text,
props: {
as: `h${level}`,
text: content?.[0].text, // content was resolved explicitly to pass via prop
},
}),
},
},
})
).toStrictEqual({
component: Text,
props: {
as: "h1",
text: "Hello from rich text",
},
content: [{ content: "Hello from rich text" }],
});

// empty content
expect(resolveNode(emptyNode)).toStrictEqual({
component: "br",
Expand Down
Loading

0 comments on commit bb07726

Please sign in to comment.