Giter Club home page Giter Club logo

natterstefan / react-component-catalog Goto Github PK

View Code? Open in Web Editor NEW
8.0 3.0 1.0 4.98 MB

react-component-catalog is a library for registering, retrieving, and rendering React components dynamically based on defined conditions.

Home Page: https://www.npmjs.com/package/react-component-catalog

License: Apache License 2.0

JavaScript 13.58% TypeScript 86.42%
react-components react-catalog react-registry registry react-component-registry react-component-catalog react-component-library

react-component-catalog's Introduction

React-Component-Catalog

npm version Build Status Coverage Status GitHub license

Dependencies Known Vulnerabilities Commitizen friendly lerna

React-Component-Catalog is a library for individually registering, retrieving, and rendering React components based on your own conditions (eg. different component for various clients, sites, ...).

Getting started

npm i react-component-catalog --save

# or
yarn add react-component-catalog

Then install the correct versions of each peerDependency package, which are listed by the command:

npm info "react-component-catalog@latest" peerDependencies

If using npm 5+, use this shortcut:

npx install-peerdeps --dev react-component-catalog

# or
yarn add react-component-catalog -D --peer

Upgrade from 1.x.x to 2.0.0

Catalog Data Structure changes

When upgrading to 2.0.0, one needs to change the Catalog's data structure.

// catalog.js
- import { Catalog } from 'react-component-catalog'
import Button from './button'

-const catalog = new Catalog({
-  components: {
-    Button,
-  },
-})
+const catalog = {
+  Button,
+)

export default catalog

CatalogProvider changes

Previously, CatalogProvider rendered it's children with an empty catalog, when none was provided. In 2.x it renders null instead. Same happens, when no child component is provided.

import { CatalogProvider } from 'react-component-catalog'
import catalog from './catalog' // your apps catalog

const App = () => (
- <CatalogProvider catalog={new Catalog({ components: catalog })}>
+ <CatalogProvider catalog={catalog}>
    <div>Hello</div>
  </CatalogProvider>
)

CatalogProvider accepts an object and no instance of Catalog anymore.

useCatalog and catalog changes

getComponent does not return null anymore when a component is not found, instead it returns undefined.

import React from 'react'
import CatalogComponent, { useCatalog } from 'react-component-catalog'

const App = () => {
- const { catalog } = useCatalog()
+ const catalog = useCatalog()

- console.log('available components', catalog._components)
+ console.log('available components', catalog._catalog)

  const Button = catalog.getComponent('Button')

  // ...
}

Catalog changes

Catalog is not exported anymore, so code like does not work anymore:

- import { Catalog } from 'react-catalog-component'

CatalogComponent and Module Augmentation

The CatalogComponents interface can be augmented to add more typing support.

// react-component-catalog.d.ts
declare module 'react-component-catalog' {
  export interface CatalogComponents {
    Title: React.FunctionComponent<{}>
  }
}

Whenever you use the CatalogComponent now you can do the following to get full typing support (opt-in feature). When you do not provide the interface, any string, string[] or Record<string, any> value for component is allowed.

const App = () => (
  <CatalogComponent<CatalogComponents> component="Title">
    Hello World
  </CatalogComponent>
)

// this works too, but `component` has no typing support
const App = () => (
  <CatalogComponent component="Title">Hello Base</CatalogComponent>
)

Attention: it is recommended to use CatalogComponents only when it was augmented. Because it represents an empty interface and without adding your own custom properties it will match everything.

Basic Usage

Create a Catalog

// button.js
import React from 'react'

const Button = props => <button>{props.children}</button>

export default Button
// catalog.js
import Button from './button'

const catalog = {
  Button,
}

export default catalog

Create a nested Catalog

It is also possible to add a nested components-object to the Catalog. This allows registering variations of a component. Take an article for instance. You might want to register different types of the component. There might be a AudioArticle, VideoArticle and a BaseArticle component you want to use. You can add them to the catalog like this:

// catalog.js
// different types of articles
import AudioArticle from './audio-article'
import BaseArticle from './base-article'
import VideoArticle from './video-article'

const catalog = {
  ArticlePage: {
    AudioArticle,
    BaseArticle,
    VideoArticle,
  },
}

export default catalog

And you could later use it like this:

// app.js
import React from 'react'
import CatalogComponent, { useCatalog } from 'react-component-catalog'

const App = props => {
  const { isAudioArticle, isVideoArticle } = props
  const catalog = useCatalog()

  // get the ArticlePage object from the catalog
  const ArticlePage = catalog.getComponent('ArticlePage')

  // or get them one by one with one of the following methods
  // const BaseArticle = catalog.getComponent('ArticlePage.BaseArticle')
  // <CatalogComponent component="ArticlePage.BaseArticle" />

  if (isAudioArticle) {
    return <ArticlePage.AudioArticle {...props} />
  }

  if (isVideoArticle) {
    return <ArticlePage.VideoArticle {...props} />
  }

  return <ArticlePage.BaseArticle {...props} />
}

export default App

Create a CatalogProvider

// index.js
import React from 'react'
import ReactDOM from 'react-dom'

import { CatalogProvider } from 'react-component-catalog'
import catalog from './catalog'
import App from './app'

ReactDOM.render(
  <CatalogProvider catalog={catalog}>
    <App />
  </CatalogProvider>,
  document.getElementById('_root'),
)

Nesting CatalogProvider

<CatalogProvider /> can be nested, whereas the inner provider will extend and overwrite the parent provider.

// setup catalogs
const catalog = {
  OuterComponent: () => <div>OuterComponent</div>,
  Title: ({ children }) => <h1>OuterTitle - {children}</h1>,
}

const innerCatalog = {
  InnerComponent: () => <div>InnerComponent</div>,
  Title: ({ children }) => <h2>InnerTitle - {children}</h2>, // inner CatalogProvider overwrites Title of the outer catalog
}

// usage
const App = () => (
  <CatalogProvider catalog={catalog}>
    <CatalogProvider catalog={innerCatalog}>
      <Content />
    </CatalogProvider>
  </CatalogProvider>
)

<Content /> can access components inside the catalog and innerCatalog. If the innerCatalog contains a component with the same name than in the catalog it will overwrite it. In this case <Title /> gets overwritten in the inner provider.

Import and use the catalog (with react-hooks)

// app.js
import React from 'react'
// useCatalog is a react-hook
import CatalogComponent, { useCatalog } from 'react-component-catalog'

const App = () => {
  const catalog = useCatalog()
  const Button = catalog.getComponent('Button')

  // you can also first check if it exists
  const hasButton = catalog.hasComponent('Button')

  // or you use them with the <CatalogComponent /> component
  return (
    <div>
      <CatalogComponent component="Title">Hello Client1</CatalogComponent>
      <CatalogComponent
        component="Card"
        {/* the fallbackComponent can either be a new component, or a component
          from the catalog */}
        fallbackComponent={() => <div>Component not found</div>}
        { /* fallbackComponent="FallbackComponent" */ }
      >
        Hello Card
      </CatalogComponent>
      {Button && <Button />}
    </div>
  )
}

export default App

Use catalog with ref

Refs provide a way to access DOM nodes or React elements created in the render method. (Source: reactjs.org)

It is possible to use react-component-catalog with ref as well. It would look similar to (works also with <CatalogComponent />):

const TestComponent = withCatalog(props => (
  <button {...props} type="button">
    Hello Button
  </button>
))

/* eslint-disable react/no-multi-comp */
class App extends React.Component {
  constructor(props) {
    super(props)
    this.setRef = React.createRef()
  }

  render() {
    // or <CatalogComponent component="TestComponent" ref={this.setRef} />
    return (
      <CatalogProvider catalog={{ TestComponent }}>
        <TestComponent ref={this.setRef} />
      </CatalogProvider>
    )
  }
}

How to build and test this package

# -- build the package --
yarn
yarn build
# -- test the package in an example app --
# run the example in watch-mode
yarn watch

# or run the example in production mode
cd packages/example
yarn build
yarn start

How to release and publish the package

This package uses standard-version and commitizen for standardizing commit messages, release tags and the changelog.

When you're ready to release, execute the following commands in the given order:

  1. git checkout master
  2. git pull origin master
  3. yarn release:prepare: select the proper version
  4. yarn release --release-as <version>: use the version selected before (e.g. beta releases: yarn release --prerelease beta --release-as major)
  5. git push --tags
  6. cd packages/react-component-catalog && yarn publish: do not select a new version.

TODO: automate and optimize scripts, see 3ba95ec and 2eb2a8b

Links

Credits

Inspired by Building a Component Registry in React by Erasmo Marín. I did not find a package implementing his thoughts and ideas in such a straightforward way. That is why, I decided to create it.

Licence

Apache 2.0

Maintainers


Stefan Natter

react-component-catalog's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

Forkers

fredrare

react-component-catalog's Issues

Typescript can not find declaration file TS7016

Bug Report

Relevant information

Typescript can not find a declaration file for module 'react-component-catalog' TS7016.

Your Environment

  • OS: Ubuntu 20.04
  • Node: v12.20.2
  • Package Version: 2.1.0

Steps to reproduce

yarn create react-app my-app --template typescript
cd my-app
yarn add react-component-catalog
yarn start

Add import { useCatalog } from 'react-component-catalog'; to any code file.
Typescript shows an error TS7016: Could not find a declaration file for module 'react-component-catalog'.

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.