Skip to content

Commit

Permalink
fix(helpers): add missing dir attribute for right-to-left languages (
Browse files Browse the repository at this point in the history
…#211)

Co-authored-by: lihbr <[email protected]>
  • Loading branch information
lihbr and lihbr authored Oct 30, 2024
1 parent c41ffb5 commit b5139ec
Show file tree
Hide file tree
Showing 3 changed files with 155 additions and 47 deletions.
14 changes: 7 additions & 7 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

61 changes: 52 additions & 9 deletions src/react-server/PrismicRichText.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import * as React from "react";
import * as prismic from "@prismicio/client";
import * as prismicR from "@prismicio/richtext";
import * as prismicT from "@prismicio/types";

import { JSXFunctionSerializer, JSXMapSerializer } from "../types";
import { LinkProps, PrismicLink } from "./PrismicLink";
Expand Down Expand Up @@ -86,25 +87,67 @@ type CreateDefaultSerializerArgs<
externalLinkComponent?: React.ComponentType<LinkProps>;
};

const getDir = (node: prismicT.RTAnyNode): "rtl" | undefined => {
if ("direction" in node && node.direction === "rtl") {
return "rtl";
}
};

const createDefaultSerializer = <
// eslint-disable-next-line @typescript-eslint/no-explicit-any
LinkResolverFunction extends prismic.LinkResolverFunction<any>,
>(
args: CreateDefaultSerializerArgs<LinkResolverFunction>,
): JSXFunctionSerializer =>
prismicR.wrapMapSerializer({
heading1: ({ children, key }) => <h1 key={key}>{children}</h1>,
heading2: ({ children, key }) => <h2 key={key}>{children}</h2>,
heading3: ({ children, key }) => <h3 key={key}>{children}</h3>,
heading4: ({ children, key }) => <h4 key={key}>{children}</h4>,
heading5: ({ children, key }) => <h5 key={key}>{children}</h5>,
heading6: ({ children, key }) => <h6 key={key}>{children}</h6>,
paragraph: ({ children, key }) => <p key={key}>{children}</p>,
heading1: ({ node, children, key }) => (
<h1 key={key} dir={getDir(node)}>
{children}
</h1>
),
heading2: ({ node, children, key }) => (
<h2 key={key} dir={getDir(node)}>
{children}
</h2>
),
heading3: ({ node, children, key }) => (
<h3 key={key} dir={getDir(node)}>
{children}
</h3>
),
heading4: ({ node, children, key }) => (
<h4 key={key} dir={getDir(node)}>
{children}
</h4>
),
heading5: ({ node, children, key }) => (
<h5 key={key} dir={getDir(node)}>
{children}
</h5>
),
heading6: ({ node, children, key }) => (
<h6 key={key} dir={getDir(node)}>
{children}
</h6>
),
paragraph: ({ node, children, key }) => (
<p key={key} dir={getDir(node)}>
{children}
</p>
),
preformatted: ({ node, key }) => <pre key={key}>{node.text}</pre>,
strong: ({ children, key }) => <strong key={key}>{children}</strong>,
em: ({ children, key }) => <em key={key}>{children}</em>,
listItem: ({ children, key }) => <li key={key}>{children}</li>,
oListItem: ({ children, key }) => <li key={key}>{children}</li>,
listItem: ({ node, children, key }) => (
<li key={key} dir={getDir(node)}>
{children}
</li>
),
oListItem: ({ node, children, key }) => (
<li key={key} dir={getDir(node)}>
{children}
</li>
),
list: ({ children, key }) => <ul key={key}>{children}</ul>,
oList: ({ children, key }) => <ol key={key}>{children}</ol>,
image: ({ node, key }) => {
Expand Down
127 changes: 96 additions & 31 deletions test/react-server/PrismicRichText.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ it("returns <h1> if type is heading1", async () => {
];

const actual = renderJSON(<PrismicRichText field={field} />);
const expected = renderJSON(<h1>Heading 1</h1>);
const expected = renderJSON(<h1 dir={undefined}>Heading 1</h1>);

expect(actual).toStrictEqual(expected);
});
Expand All @@ -84,7 +84,7 @@ it("returns <h2> if type is heading2", async () => {
];

const actual = renderJSON(<PrismicRichText field={field} />);
const expected = renderJSON(<h2>Heading 2</h2>);
const expected = renderJSON(<h2 dir={undefined}>Heading 2</h2>);

expect(actual).toStrictEqual(expected);
});
Expand All @@ -99,7 +99,7 @@ it("returns <h3> if type is heading3", async () => {
];

const actual = renderJSON(<PrismicRichText field={field} />);
const expected = renderJSON(<h3>Heading 3</h3>);
const expected = renderJSON(<h3 dir={undefined}>Heading 3</h3>);

expect(actual).toStrictEqual(expected);
});
Expand All @@ -114,27 +114,12 @@ it("returns <h4> if type is heading4", async () => {
];

const actual = renderJSON(<PrismicRichText field={field} />);
const expected = renderJSON(<h4>Heading 4</h4>);
const expected = renderJSON(<h4 dir={undefined}>Heading 4</h4>);

expect(actual).toStrictEqual(expected);
});

it("returns <h4> if type is heading3", async () => {
const field: prismic.RichTextField = [
{
type: prismic.RichTextNodeType.heading4,
text: "Heading 4",
spans: [],
},
];

const actual = renderJSON(<PrismicRichText field={field} />);
const expected = renderJSON(<h4>Heading 4</h4>);

expect(actual).toStrictEqual(expected);
});

it("returns <h5> if type is heading4", async () => {
it("returns <h5> if type is heading5", async () => {
const field: prismic.RichTextField = [
{
type: prismic.RichTextNodeType.heading5,
Expand All @@ -144,7 +129,7 @@ it("returns <h5> if type is heading4", async () => {
];

const actual = renderJSON(<PrismicRichText field={field} />);
const expected = renderJSON(<h5>Heading 5</h5>);
const expected = renderJSON(<h5 dir={undefined}>Heading 5</h5>);

expect(actual).toStrictEqual(expected);
});
Expand All @@ -159,7 +144,7 @@ it("returns <h6> if type is heading6", async () => {
];

const actual = renderJSON(<PrismicRichText field={field} />);
const expected = renderJSON(<h6>Heading 6</h6>);
const expected = renderJSON(<h6 dir={undefined}>Heading 6</h6>);

expect(actual).toStrictEqual(expected);
});
Expand All @@ -174,7 +159,7 @@ it("returns <p /> if type is paragraph", async () => {
];

const actual = renderJSON(<PrismicRichText field={field} />);
const expected = renderJSON(<p>Paragraph bold</p>);
const expected = renderJSON(<p dir={undefined}>Paragraph bold</p>);

expect(actual).toStrictEqual(expected);
});
Expand Down Expand Up @@ -211,7 +196,7 @@ it("returns <strong /> if type is strong", async () => {

const actual = renderJSON(<PrismicRichText field={field} />);
const expected = renderJSON(
<p>
<p dir={undefined}>
<strong>strong</strong>
</p>,
);
Expand All @@ -236,7 +221,7 @@ it("returns <em /> if type is em", async () => {

const actual = renderJSON(<PrismicRichText field={field} />);
const expected = renderJSON(
<p>
<p dir={undefined}>
<em>em</em>
</p>,
);
Expand All @@ -256,7 +241,7 @@ it("returns <ul> <li> </li> </ul> if type is listItem", async () => {
const actual = renderJSON(<PrismicRichText field={field} />);
const expected = renderJSON(
<ul>
<li>listItem</li>
<li dir={undefined}>listItem</li>
</ul>,
);

Expand All @@ -275,7 +260,7 @@ it("returns <ol> <li> </li> </ol> if type is listItem", async () => {
const actual = renderJSON(<PrismicRichText field={field} />);
const expected = renderJSON(
<ol>
<li>oListItem</li>
<li dir={undefined}>oListItem</li>
</ol>,
);

Expand Down Expand Up @@ -451,7 +436,7 @@ it("Returns <PrismicLink /> when type is hyperlink", async () => {

const actual = renderJSON(<PrismicRichText field={field} />);
const expected = renderJSON(
<p>
<p dir={undefined}>
<a href={data.url} rel={undefined} target={undefined}>
hyperlink
</a>
Expand Down Expand Up @@ -492,7 +477,7 @@ it("Returns <PrismicLink /> with internalComponent from props", async () => {
<PrismicRichText internalLinkComponent={Link} field={field} />,
);
const expected = renderJSON(
<p>
<p dir={undefined}>
<a data-href="/url" data-rel={undefined} data-target={undefined}>
hyperlink
</a>
Expand Down Expand Up @@ -523,7 +508,7 @@ it("returns <span /> with label className if type is label", async () => {

const actual = renderJSON(<PrismicRichText field={field} />);
const expected = renderJSON(
<p>
<p dir={undefined}>
<span className={data.label}>label</span>
</p>,
);
Expand All @@ -542,7 +527,7 @@ it("renders line breaks as <br />", async () => {

const actual = renderJSON(<PrismicRichText field={field} />);
const expected = renderJSON(
<p>
<p dir={undefined}>
line 1<br />
line 2
</p>,
Expand All @@ -551,6 +536,86 @@ it("renders line breaks as <br />", async () => {
expect(actual).toStrictEqual(expected);
});

it("includes `dir` attribute on right-to-left languages", async () => {
const field: prismic.RichTextField = [
{
type: prismic.RichTextNodeType.heading1,
text: "Heading 1",
spans: [],
direction: "rtl",
},
{
type: prismic.RichTextNodeType.heading2,
text: "Heading 2",
spans: [],
direction: "rtl",
},
{
type: prismic.RichTextNodeType.heading3,
text: "Heading 3",
spans: [],
direction: "rtl",
},
{
type: prismic.RichTextNodeType.heading4,
text: "Heading 4",
spans: [],
direction: "rtl",
},
{
type: prismic.RichTextNodeType.heading5,
text: "Heading 5",
spans: [],
direction: "rtl",
},
{
type: prismic.RichTextNodeType.heading6,
text: "Heading 6",
spans: [],
direction: "rtl",
},
{
type: prismic.RichTextNodeType.paragraph,
text: "Paragraph",
spans: [],
direction: "rtl",
},
{
type: prismic.RichTextNodeType.listItem,
text: "listItem",
spans: [],
direction: "rtl",
},
{
type: prismic.RichTextNodeType.oListItem,
text: "oListItem",
spans: [],
direction: "rtl",
},
];

const actual = renderJSON(<PrismicRichText field={field} />);
const expected = renderJSON(
<>
<h1 dir="rtl">Heading 1</h1>
<h2 dir="rtl">Heading 2</h2>
<h3 dir="rtl">Heading 3</h3>
<h4 dir="rtl">Heading 4</h4>
<h5 dir="rtl">Heading 5</h5>
<h6 dir="rtl">Heading 6</h6>
<p dir="rtl">Paragraph</p>
<ul>
<li dir="rtl">listItem</li>
</ul>
<ol>
<li dir="rtl">oListItem</li>
</ol>
</>,
);

expect(actual).toStrictEqual(expected);
});

it("renders components from components prop", async () => {
const field: prismic.RichTextField = [
{
Expand Down

0 comments on commit b5139ec

Please sign in to comment.