Skip to content

Commit

Permalink
feat: add typescript React component examples to docs
Browse files Browse the repository at this point in the history
  • Loading branch information
mcqua007 committed Jan 15, 2025
1 parent dfcc1c4 commit aa5aded
Showing 1 changed file with 205 additions and 15 deletions.
220 changes: 205 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,26 +103,216 @@ convertSchemaToHtml(richTextResponse, options)
<li class="text-sm md:text-base">oranges</li>
<li class="text-sm md:text-base">bananas</li>
</ol>
...
```

React/Hydrogen example:
**React/Hydrogen Component Example**

```javascript
export default RenderedHTML(){
const richTextResponse = await getRichTextFromShopify()
```typescript
// @/components/RichtextToHTML.tsx
import {convertSchemaToHtml} from '@thebeyondgroup/shopify-rich-text-renderer';
import type {Schema, Options} from '@thebeyondgroup/shopify-rich-text-renderer';
import {useEffect, useState} from 'react';

/**
* Default options for the HTML conversion, using Tailwind CSS classes
* for styling, you can update these to suit your specific needs
**/

const defaultOptions = {
scoped: false,
newLineToBreak: false, // convert new line character to <br/>
classes: {
p: 'mt-3 text-lg', // paragraph classes
h1: 'mb-4 text-2xl md:text-4xl', // heading1 classes
h2: 'mb-4 text-xl md:text-3xl', // heading2 classes
h3: 'mb-3 text-lg md:text-2xl', // heading3 classes
h4: 'mb-3 text-base md:text-lg', // heading4 classes
h5: 'mb-2.5 text-sm md:text-base', // heading5 classes
h6: 'mb-2 text-xs md:text-sm', // heading6 classes
ol: 'my-3 ml-3 flex flex-col gap-y-2', // order list classes
ul: 'my-3 ml-3 flex flex-col gap-y-2', // unordered list classes
li: 'text-sm md:text-base', // list item classes
a: 'underline text-blue-500 hover:text-blue-700', // anchor/link classes
strong: 'font-medium', // bold/strong classes
em: 'font-italic', // italic/em classes
},
};

/**
* Fetch shopify schema from metaobjects API, you can update
* this function to suite your needs better or completely
* remove it if not needed
**/

const fetchSchema = async (url: string) => {
const res = await fetch(url);
return await res.json();
};

/**
* React component that converts a schema to HTML, has default classes
* that can be overwritten if no schema exists the user can pass the apiRoute as prop
**/

interface RichtextToHtmlProps {
schema: string | Schema | Schema[];
options?: Options | string | boolean;
apiRoute?: string;
className?: string;
}

export default function RichtextToHTML({
schema,
options,
apiRoute,
className,
}: RichtextToHtmlProps) {
const [currentSchema, setCurrentSchema] = useState(schema || null);

/**
* Fetch schema from API route if no schema is passed,
* you can remove this if not needed along with the
* apiRoute prop & current schema state
**/
useEffect(() => {
async function fetchData() {
if (!currentSchema && apiRoute) {
const richTextSchema = await fetchSchema(apiRoute);
setCurrentSchema(richTextSchema as Schema | Schema[]);
}
}
fetchData();
}, [currentSchema, apiRoute]);

//options passed via props override default options (classes,scoped, newLineToBreak) etc...
const combinedOptions = {
...defaultOptions,
...(typeof options === 'object' && options !== null ? options : {}),
};

const html = currentSchema
? convertSchemaToHtml(currentSchema, combinedOptions)
: '';
return (
<>
<div
className="html"
dangerouslySetInnerHTML={{
__html: convertSchemaToHtml(richTextResponse),
}}
/>
<div>
</>
)
<>
<div className={className} dangerouslySetInnerHTML={{__html: html}} />
</>
);
}
```

**React Component Example without fetch fallback**

```typescript
// @/components/RichtextToHTML.tsx
import {convertSchemaToHtml} from '@thebeyondgroup/shopify-rich-text-renderer';
import type {Schema, Options} from '@thebeyondgroup/shopify-rich-text-renderer';
import {useEffect, useState} from 'react';

/**
* Default options for the HTML conversion, using Tailwind CSS classes
* for styling, you can update these to suit your specific needs
**/

const defaultOptions = {
scoped: false,
newLineToBreak: false, // convert new line character to <br/>
classes: {
p: 'mt-2 text-sm', // paragraph classes
h1: 'mb-4 text-3xl md:text-4xl', // heading1 classes
h2: 'mb-4 text-2xl md:text-3xl', // heading2 classes
a: 'underline text-gray-700 hover:text-blue-700 text-sm', // anchor/link classes
strong: 'font-semibold', // bold/strong classes
em: 'font-italic', // italic/em classes
},
};

/**
* React component that converts a Shopify Richtext schema to HTML
**/

interface RichtextToHtmlProps {
schema: string | Schema | Schema[];
options?: Options | string | boolean;
className?: string;
}

export default function RichtextToHTML({schema, options, className}: RichtextToHtmlProps) {

//options passed via props override default options (classes,scoped, newLineToBreak) etc...
const combinedOptions = {
...defaultOptions,
...(typeof options === 'object' && options !== null ? options : {}),
};

const html = convertSchemaToHtml(currentSchema, combinedOptions)
return (
<>
<div className={className} dangerouslySetInnerHTML={{__html: html}} />
</>
);
}
```

**Example of the react RichtextToHTML components in use**

```typescript
// App.tsx
import React from 'react'
import RichTextToHTML from './RichTextToHTML'

// Custom schema for/mock rich text metaobject get request
const schema = {
type: 'root',
children: [
{
type: 'heading',
level: 2,
children: [{ type: 'text', value: 'Custom Heading 2' }],
},
{
type: 'paragraph',
children: [{ type: 'text', value: 'This is a custom paragraph.' }],
},
],
}

// Custom options for demonstration of overriding defaults.
// Note: you probably wouldn't need to set the scoped class name & apply unique classes per element
const customOptions = {
scoped: 'custom-scope',
classes: {
p: 'text-lg text-slate-800 my-2',
h2: 'text-2xl md:text-4xl font-semibold leading-none tracking-wide mb-2',
},
newLineToBreak: true,
}

// Main React App Component
const App = () => {
return (
<div className="container flex flex-col gap-4 mx-auto p-4">
<h1 className="text-3xl font-bold mb-6">Shopify Storefront</h1>
<section>
<h2 className="text-xl font-semibold">Product Description</h2>
<RichTextToHTML className="my-5 py-3" schema={schema} options={customOptions} />
</section>
<section>
<h2 className="text-xl font-semibold">User Profile</h2>
{/**
* Example using fallback fetch request. For demonstration purposes.
*/}
<RichTextToHTML
className="my-5 py-3"
options={customOptions}
apiRoute="/api/metaobjects/richtext/user-profile?api-key=tH3BeY0ndGr0vp"
/>
</section>
</div>
)
}

export default App
```

Here is a [JSFiddle Demo](https://jsfiddle.net/r2d4wsna/) that shows a working example.

0 comments on commit aa5aded

Please sign in to comment.