https://github.com/natterstefan/react-component-catalog
react-component-catalog is a library for registering, retrieving, and rendering React components dynamically based on defined conditions.
https://github.com/natterstefan/react-component-catalog
react-catalog react-component-catalog react-component-library react-component-registry react-components react-registry registry
Last synced: 6 months ago
JSON representation
react-component-catalog is a library for registering, retrieving, and rendering React components dynamically based on defined conditions.
- Host: GitHub
- URL: https://github.com/natterstefan/react-component-catalog
- Owner: natterstefan
- License: apache-2.0
- Created: 2019-01-31T19:18:01.000Z (about 7 years ago)
- Default Branch: master
- Last Pushed: 2022-01-22T22:41:28.000Z (about 4 years ago)
- Last Synced: 2025-03-27T15:48:35.439Z (12 months ago)
- Topics: react-catalog, react-component-catalog, react-component-library, react-component-registry, react-components, react-registry, registry
- Language: TypeScript
- Homepage: https://www.npmjs.com/package/react-component-catalog
- Size: 4.86 MB
- Stars: 8
- Watchers: 2
- Forks: 1
- Open Issues: 20
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- Funding: .github/FUNDING.yml
- Codeowners: .github/CODEOWNERS
Awesome Lists containing this project
README
# React-Component-Catalog
[](https://badge.fury.io/js/react-component-catalog)
[](https://travis-ci.com/natterstefan/react-component-catalog)
[](https://coveralls.io/github/natterstefan/react-component-catalog?branch=master) [](https://github.com/natterstefan/react-component-catalog/blob/master/LICENCE)
[](https://github.com/natterstefan/react-component-catalog/blob/master/package.json)
[](https://snyk.io/test/github/natterstefan/react-component-catalog)
[](http://commitizen.github.io/cz-cli/)
[](https://lerna.js.org/)
[React-Component-Catalog](https://github.com/natterstefan/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
```bash
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:
```bash
npm info "react-component-catalog@latest" peerDependencies
```
If using npm 5+, use this shortcut:
```bash
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.
```diff
// 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.
```diff
import { CatalogProvider } from 'react-component-catalog'
import catalog from './catalog' // your apps catalog
const App = () => (
-
+
Hello
)
```
`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`.
```diff
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:
```diff
- import { Catalog } from 'react-catalog-component'
```
### `CatalogComponent` and Module Augmentation
The `CatalogComponents` interface can be augmented to add more typing support.
```tsx
// 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` value for `component` is allowed.
```tsx
const App = () => (
component="Title">
Hello World
)
// this works too, but `component` has no typing support
const App = () => (
Hello Base
)
```
_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](https://stackoverflow.com/a/58512513/1238150).
## Basic Usage
### Create a Catalog
```jsx
// button.js
import React from 'react'
const Button = props => {props.children}
export default Button
```
```jsx
// 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:
```jsx
// 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:
```jsx
// 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')
//
if (isAudioArticle) {
return
}
if (isVideoArticle) {
return
}
return
}
export default App
```
### Create a CatalogProvider
```jsx
// 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(
,
document.getElementById('_root'),
)
```
#### Nesting CatalogProvider
`` can be nested, whereas the inner provider will extend and
overwrite the parent provider.
```js
// setup catalogs
const catalog = {
OuterComponent: () =>
OuterComponent,
Title: ({ children }) => OuterTitle - {children}
,
}
const innerCatalog = {
InnerComponent: () =>
InnerComponent,
Title: ({ children }) => InnerTitle - {children}
, // inner CatalogProvider overwrites Title of the outer catalog
}
// usage
const App = () => (
)
```
`` 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 `` gets overwritten in the inner
provider.
### Import and use the catalog (with react-hooks)
```jsx
// 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 component
return (
Hello Client1
Component not found}
{ /* fallbackComponent="FallbackComponent" */ }
>
Hello Card
{Button && }
)
}
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](https://reactjs.org/docs/refs-and-the-dom.html))
It is possible to use `react-component-catalog` with `ref` as well. It would
look similar to (works also with ``):
```js
const TestComponent = withCatalog(props => (
Hello Button
))
/* eslint-disable react/no-multi-comp */
class App extends React.Component {
constructor(props) {
super(props)
this.setRef = React.createRef()
}
render() {
// or
return (
)
}
}
```
## How to build and test this package
```bash
# -- build the package --
yarn
yarn build
```
```bash
# -- 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](https://github.com/conventional-changelog/standard-version)
and [commitizen](https://github.com/commitizen/cz-cli) 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 `: 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](https://github.com/natterstefan/react-component-catalog/pull/57/commits/3ba95ec08af5dadc13033ecd28e9c285b3cced72#diff-7ae45ad102eab3b6d7e7896acd08c427a9b25b346470d7bc6507b6481575d519R10)
and [2eb2a8b](https://github.com/natterstefan/react-component-catalog/pull/57/commits/2eb2a8b47500523f13ea5055961be469a2f52646)
### Links
- [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0-beta.4/)
- [conventional-changelog](https://github.com/conventional-changelog/conventional-changelog)
- [Modules Important to Conventional Changelog Ecosystem](https://github.com/conventional-changelog/conventional-changelog#modules-important-to-conventional-changelog-ecosystem)
- [semantic-release](https://github.com/semantic-release/semantic-release)
(standard-version alternative, with extended CI support)
- [commitlint](https://github.com/conventional-changelog/commitlint)
- [npm-dedupe when eg. multiple @types/\* versions are installed](https://docs.npmjs.com/cli/dedupe.html)
- [React Type Reference](https://flow.org/en/docs/react/types/)
- [Generics while using React.forwardRef](https://stackoverflow.com/a/58473012/1238150)
## Credits
Inspired by [Building a Component Registry in React by Erasmo Marín](https://medium.com/smartboxtv-engineering/building-a-component-registry-in-react-4504ca271e56).
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](LICENCE)
## Maintainers