Skip to content

Commit

Permalink
fix: align the naming of render types
Browse files Browse the repository at this point in the history
  • Loading branch information
thebuilder committed May 5, 2024
1 parent 28582f9 commit f88bdf2
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 38 deletions.
92 changes: 61 additions & 31 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,64 +3,92 @@
[![npm version][npm-version-src]][npm-version-href]
[![License][license-src]][license-href]

A collection of React components for working with the
Umbraco [Content Delivery API](https://docs.umbraco.com/umbraco-cms/reference/content-delivery-api).
A collection of React components for working with the Umbraco
[Content Delivery API](https://docs.umbraco.com/umbraco-cms/reference/content-delivery-api).

## Install

Install the `@charlietango/react-umbraco` package with your package manager of choice.
Install the `@charlietango/react-umbraco` package with your package manager of
choice.

```sh
npm install @charlietango/react-umbraco
```

### `<UmbracoRichText>`

Takes the rich text property from the Umbraco Content Delivery API and renders it with React.
Takes the rich text property from the Umbraco Content Delivery API and renders
it with React.

### Props

- `element`: The rich text property from the Umbraco Content Delivery API.
- `renderBlock`: Render a specific block type.
- `renderNode`: Overwrite the default rendering of a node. Return `undefined` to render the default node. Return `null` to skip rendering the node.
- `renderNode`: Overwrite the default rendering of a node. Return `undefined` to
render the default node. Return `null` to skip rendering the node.

When passing the `renderBlock` and `renderNode` props, consider making them
static functions (move them outside the consuming component) to avoid
unnecessary re-renders.

```tsx
import { UmbracoRichText } from "@charlietango/react-umbraco";
import {
UmbracoRichText,
RenderBlockContext,
RenderNodeContext,
} from "@charlietango/react-umbraco";
import Image from "next/image";
import Link from "next/link";

const MyComponent = ({ data }) => {
function renderNode({ tag, children, attributes }: RenderNodeContext) {
switch (tag) {
case "a":
return <Link {...attributes}>{children}</Link>;
case "p":
return (
<p className="text-lg" {...attributes}>
{children}
</p>
);
default:
// Return `undefined` to render the default HTML node
return undefined;
}
}

function renderBlock({ content }: RenderBlockContext) {
switch (content?.contentType) {
// Switch over your Umbraco document types that can be rendered in the Rich Text blocks
case "imageBlock":
return <Image {...content.properties} />;
default:
return null;
}
}

function RichText({ data }) {
return (
<UmbracoRichText
element={data.richText}
renderNode={({ tag, children, attributes }) => {
switch (tag) {
case "a":
return <Link {...attributes}>{children}</Link>;
default:
return undefined;
}
}}
renderBlock={({ content }) => {
switch (content?.contentType) {
case "imageBlock":
return <Image {...content.properties} />;
default:
return null;
}
}}
renderNode={renderNode}
renderBlock={renderBlock}
/>
);
};
}
```

#### Blocks

You can augment the `renderBlock` method with the generated OpenAPI types for the Umbraco Content Delivery API.
That way you can correctly filter the blocks you are rendering, based on the `contentType`, and get the
associated `properties`.
Create `types/react-umbraco.d.ts`, and augment the `UmbracoBlockItemModel` interface with your applications definition
for `ApiBlockItemModel`.
You can augment the `renderBlock` method with the generated OpenAPI types from
Umbraco Content Delivery API. That way you can correctly filter the blocks you
are rendering, based on the `contentType`, and get the associated `properties`.
Create `types/react-umbraco.d.ts`, and augment the `UmbracoBlockItemModel`
interface with your applications definition for `ApiBlockItemModel`.

To generate the types, you'll want to use the
[Delivery Api Extensions](https://marketplace.umbraco.com/package/umbraco.community.deliveryapiextensions)
package, alongside a tool to generate the types from the OpenAPI schema, like
[openapi-typescript](https://openapi-ts.pages.dev/).

**types/react-umbraco.d.ts**

Expand All @@ -77,7 +105,9 @@ declare module "@charlietango/react-umbraco" {

<!-- Badges -->

[npm-version-src]: https://img.shields.io/npm/v/@charlietango/react-umbraco?style=flat&colorA=080f12&colorB=1fa669
[npm-version-src]:
https://img.shields.io/npm/v/@charlietango/react-umbraco?style=flat&colorA=080f12&colorB=1fa669
[npm-version-href]: https://npmjs.com/package/@charlietango/react-umbraco
[license-src]: https://img.shields.io/github/license/charlie-tango/react-umbraco.svg?style=flat&colorA=080f12&colorB=1fa669
[license-src]:
https://img.shields.io/github/license/charlie-tango/react-umbraco.svg?style=flat&colorA=080f12&colorB=1fa669
[license-href]: https://github.com/charlie-tango/react-umbraco/blob/main/LICENSE
4 changes: 4 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -73,5 +73,9 @@
"biome check --apply --no-errors-on-unmatched"
],
"*.md": ["prettier --write"]
},
"prettier": {
"proseWrap": "always",
"printWidth": 80
}
}
15 changes: 9 additions & 6 deletions src/UmbracoRichText.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,10 @@ interface BaseBlockItemModel {
*/
export type UmbracoBlockItemModel = {};

type BlockItemModel = Overwrite<BaseBlockItemModel, UmbracoBlockItemModel>;
export type RenderBlockContext = Overwrite<
BaseBlockItemModel,
UmbracoBlockItemModel
>;

interface RouteAttributes {
path: string;
Expand All @@ -59,7 +62,7 @@ interface NodeMeta {
* Props for rendering a single node in the rich text.
* A node is any HTML element that is part of the rich text.
*/
export type RenderNodeProps = {
export type RenderNodeContext = {
children?: React.ReactNode;
meta: NodeMeta;
} & (
Expand All @@ -84,16 +87,16 @@ interface RichTextProps {
tag: string;
attributes?: Record<string, unknown>;
elements?: RichTextElementModel[];
blocks?: Array<BlockItemModel>;
blocks?: Array<RenderBlockContext>;
}
| undefined;
renderBlock?: (block: BlockItemModel) => React.ReactNode;
renderBlock?: (block: RenderBlockContext) => React.ReactNode;
/**
* Render an HTML node with custom logic.
* @param node
* @returns A React node, `null` to render nothing, or `undefined` to fallback to the default element
*/
renderNode?: (node: RenderNodeProps) => React.ReactNode | undefined;
renderNode?: (node: RenderNodeContext) => React.ReactNode | undefined;
}

type RichTextElementModel =
Expand Down Expand Up @@ -129,7 +132,7 @@ function RichTextElement({
meta,
}: {
element: RichTextElementModel;
blocks: Array<BlockItemModel> | undefined;
blocks: Array<RenderBlockContext> | undefined;
meta:
| {
ancestor?: string;
Expand Down
6 changes: 5 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,6 @@
export { UmbracoRichText } from "./UmbracoRichText";
export type { UmbracoBlockItemModel, RenderNodeProps } from "./UmbracoRichText";
export type {
UmbracoBlockItemModel,
RenderBlockContext,
RenderNodeContext,
} from "./UmbracoRichText";

0 comments on commit f88bdf2

Please sign in to comment.