Giter VIP home page Giter VIP logo

react-components's Introduction

Kontent.ai's React Components

The package containing React components useful when processing Kontent.ai's data to the site.

Install

npm install @kontent-ai/react-components

Typescript

Components exports their typescript definitions so that you know what data format you need to provide via props and what data format expect from function prop callback arguments.

Rich text element component

Rich text elements from Kontent.ai could be resolved to React components using html-react-parser (based on this article)

This package should make the usage easier. Basically by loading the rich text data and use these components to provide this data and resolver functions.

More showcases could be found in RichTextElement.spec.tsx.

import { createDeliveryClient, Elements } from '@kontent-ai/delivery-sdk';
import { isComponent, isLinkedItem, RichTextElement } from '@kontent-ai/react-components';
import { Element as DomHandlerElement } from 'domhandler';

// ...

const client =  createDeliveryClient({
    environmentId: '<YOUR ENVIRONMENT ID>'
});

const response = await client.item("<YOUR ITEM CODENAME>"))
    .toPromise();

// ...

<RichTextElement
    richTextElement={response.item.elements["bio"] as Elements.RichTextElement}
    resolvers={{
        resolveLinkedItem: (linkedItem, { domElement, domToReact }) => {
            if (isComponent(domElement)) {
                return (
                    <>
                        <h1>Component</h1>
                        <pre>{JSON.stringify(linkedItem, undefined, 2)}</pre>;
                    </>
                );
            }
            if (isLinkedItem(domElement)) {
                return (
                    <>
                        <h1>Linked item</h1>
                        <pre>{JSON.stringify(linkedItem, undefined, 2)}</pre>;
                    </>
                );
            }
            throw new Error("Unknown type of the linked item's dom node");
        },
        resolveImage: (image, { domElement, domToReact }): JSX.Element => (
            <img
                src={image.url}
                alt={image.description ? image.description : image.imageId}
                width="200"
            />
        ),
        resolveLink: (link, { domElement, domToReact }): JSX.Element => (
            <a href={`/${link.type}/${link.urlSlug}`}>
                {domToReact(domElement.children)}
            </a>
        ),
        resolveDomNode: ({ domNode, domToReact }) => {
            if (domNode instanceof DomHandlerElement && domNode.name === 'table') {
                return <div className="table-wrapper">{domToReact([domNode])}</div>;
            }
        }
    }}
/>

Multilevel resolving

If you want to resolve multiple levels of components and linked items in rich text, it is possible to use the component recursively and reuse the resolving logic.

There is an example when rich text can have row components, and these can contains column components with html.

// resolving functionality
const resolveLinkedItemsRecursively: ResolveLinkedItemType = (
  linkedItem,
  _domNode
) => {
  switch (linkedItem?.system.type) {
    case "row":
      return (
        <div className="row">
          <RichTextElement
            richTextElement={
              linkedItem?.elements["columns"] as Elements.RichTextElement
            }
            // Recursively resolve items in the rich text
            resolvers={{
              resolveLinkedItem: resolveLinkedItemsRecursively,
            }}
          />
        </div>
      );
    case "column":
      return (
        <div className="column">
          <RichTextElement
            richTextElement={
              linkedItem?.elements["content"] as Elements.RichTextElement
            }
            resolvers={{
              resolveLinkedItem: resolveLinkedItemsRecursively,
            }}
          />
        </div>
      );
  }
};

// SO the top level rich text would define
<RichTextElement
  richTextElement={
    multiLevelComponentsRichTextItem.item.elements[
      "content"
    ] as Elements.RichTextElement
  }
  resolvers={{
    resolveLinkedItem: resolveLinkedItemsRecursively,
  }}
/>;

โš  Recursive resolution could lead to infinite loops, if you have a circular dependency. To avoid that, you can store the codenames of already processed items and if you hit the same one during resolution, break the resolution chain - this could happen only if you use linked items, not components in rich text.

Return vs. Mutate DOM Node

By returning the react components in any of the resolvers functions, you stop traversing the DOM tree under the current DOM node (its children). If you just want to avoid that behavior, you can mutate the provided DOM node and return undefined.

In this showcase a simple html is being resolved and for <p> tags and all <strong> tags a proper class is being set without stopping and traversing.

<RichTextElement
  richTextElement={{
    ...emptyRichText,
    value: "<p>Lorem ipsum with <strong>bold text</strong></p>",
  }}
  resolvers={{
    resolveDomNode: ({ domNode, domToReact }) => {
      if (domNode instanceof DomHandlerElement) {
        if (domNode.name === "strong") {
          domNode.attribs.class = domNode.attribs.class
            ? domNode.attribs.class + " strongClass"
            : "strongClass";
          return undefined;
        } else if (domNode.name === "p") {
          domNode.attribs.class = domNode.attribs.class
            ? domNode.attribs.class + " pClass"
            : "pClass";
          return undefined;
        }
      }
    },
  }}
/>

The outcome is

<p className="pClass">
  Lorem ipsum with
  <strong className="strongClass"> bold text </strong>
</p>

Feedback

If you have any feedback, feel free to submit an issue or open a PR!

react-components's People

Contributors

chekrd avatar dependabot[bot] avatar ivankiral avatar jirilojda avatar kontent-ai-bot avatar pokornyd avatar simply007 avatar

Stargazers

 avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

react-components's Issues

Set Kontent DAPI SDK as peer

Move from devdependency for peer + devDependency.

and set version to ^11.13.0 (ar the latest in time of implementation)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.