npm package: @react-app-composer/core
Description: Compose your React app using react-app-composer. You can create many apps from the same elements
Author: Mariusz Przodała
Latest version: 0.2.0

# REACT APP COMPOSER

#### Requirements

- React v18
- react-router-dom
- eventrix

#### Description

Compose your React app with react-app-composer.

#### Installation

```bash
npm i @react-app-composer/core react-router-dom eventrix --save
```

##### Basic usage

```js
import { Composer, DynamicModule } from "@react-app-composer/core";
import ReactDOM from "react-dom/client";
import config from "./config";

const root = ReactDOM.createRoot(document.getElementById("root"));

root.render(
    <Composer config={config} />
);
```

#### Recommended directories structure

```
/src
    /modules
        /Home
            Home.jsx
            index.js
        /Menu
            /components
                MenuItem.jsx
            Menu.jsx
            index.js
    /services
        /Authentication
            Authentication.js
            index.js
    /layouts
        /Basic
            Basic.jsx
            index.js
        /Login
            Login.jsx
            index.js
    index.js
webpack.config.js
package.json
```

#### Config file example in JSON format

```json
{
  "services": {
    "authentication": {
      "dependencies": [
        "ajax"
      ],
      "load": "/services/authentication/1.0.0/index.js",
      "data": {
        "clientId": "services.frontend",
        "userTokenKey": "AUTHENTICATION_TOKEN",
        "urls": {
          "authServer": "http://somedomain.com/auth/realms/test/protocol/openid-connect"
        }
      }
    }
  },
  "modules": {
    "logo": {
      "dependencies": [],
      "data": {
        "logoUrl": "https://some-domain.com/images/logo.png"
      },
      "load": "/modules/logo/1.0.0/index.js"
    },
    "home": {
      "dependencies": [
        "config"
      ],
      "load": "/modules/home/1.0.0/index.js",
      "events": [],
      "data": {
        "someStaticData": "foo"
      }
    },
    "login": {
      "dependencies": [
        "authentication"
      ],
      "load": "/modules/login/1.0.0/index.js",
      "events": [],
      "data": {
        "someStaticData": "foo"
      }
    },
    "mainMenu": {
      "dependencies": [
        "authentication",
        "config"
      ],
      "load": "/modules/menu/1.0.0/index.js"
    }
  },
  "layouts": {
    "basic": {
      "dependencies": [],
      "load": "/layoyts/basic/1.0.0/index.js",
      "regions": {
        "leftnav": {
          "modules": [
            "logo",
            "mainMenu"
          ]
        },
        "topbar": {
          "modules": []
        },
        "main": {
          "modules": []
        },
        "footer": {
          "modules": []
        }
      },
      "data": {}
    },
    "login": {
      "dependencies": [],
      "load": "/layoyts/login/1.0.0/index.js",
      "regions": {
        "topbar": {
          "modules": [
            "logo"
          ]
        },
        "main": {
          "modules": []
        },
        "footer": {
          "modules": []
        }
      },
      "data": {}
    }
  },
  "routes": {
    "login": {
      "path": "/login",
      "layout": "login",
      "menuLabel": "Login",
      "title": "Login page",
      "description": "Login to application",
      "regions": {
        "main": {
          "modules": [
            "login"
          ]
        }
      }
    },
    "homePage": {
      "path": "/",
      "layout": "basic",
      "menuLabel": "Home",
      "title": "Home page",
      "description": "Home page with login",
      "regions": {
        "main": {
          "modules": [
            "home"
          ]
        }
      }
    },
    "test1": {
      "path": "/test23",
      "layout": "basic",
      "private": true,
      "menuLabel": "Test 1",
      "title": "Test 1",
      "description": "Test 1 page",
      "regions": {
        "main": {
          "modules": []
        }
      }
    }
  },
  "settings": {}
}
```

#### Config file example in JS format

```js
// layouts
import loadBasicLayout from './layouts/Basic';
import loadLoginLayout from "./layouts/Login";

// modules
import loadLogoModule from "./modules/Logo";
import loadHomeModule from "./modules/Home";
import loadLoginModule from "./modules/Login";
import loadMainMenu from "./modules/MainMenu";

// components
import loadLoaderComponent from "./components/Loader";

// services
import loadKeycloakAuthenticationService from "./services/KeycloakAuthentication";

const config = {
    services: {
        authentication: {
            dependencies: ['ajax'],
            load: loadKeycloakAuthenticationService,
            data: {
                clientId: 'services.frontend',
                userTokenKey: 'AUTHENTICATION_TOKEN',
                urls: {
                    authServer: 'http://somedomain.com/auth/realms/test/protocol/openid-connect'
                }
            }
        },
    },
    components: {
        loader: {
            load: loadLoaderComponent,
            data: {
                size: 'large'
            }
        }
    },
    modules: {
        logo: {
            dependencies: [],
            data: {
                logoUrl: 'https://some-domain.com/images/logo.png',
            },
            load: loadLogoModule,
        },
        home: {
            dependencies: ['config'],
            load: loadHomeModule,
            events: [],
            data: {
                someStaticData: 'foo',
            },
        },
        login: {
            dependencies: ['authentication'],
            load: loadLoginModule,
            events: [],
            data: {
                someStaticData: 'foo',
            },
        },
        mainMenu: {
            dependencies: ['authentication', 'config'],
            load: loadMainMenu,
        },
    },
    layouts: {
        basic: {
            dependencies: [],
            load: loadBasicLayout,
            regions: {
                leftnav: {
                    modules: ['logo', 'mainMenu']
                },
                topbar: {
                    modules: [],
                },
                main: {
                    modules: []
                },
                footer: {
                    modules: []
                }
            },
            data: {},
        },
        login: {
            dependencies: [],
            load: loadLoginLayout,
            regions: {
                topbar: {
                    modules: ['logo'],
                },
                main: {
                    modules: []
                },
                footer: {
                    modules: []
                }
            },
            data: {},
        },
    },
    routes: {
        login: {
            path: '/login',
            layout: 'login',
            menuLabel: 'Login',
            title: 'Login page',
            description: 'Login to application',
            regions: {
                main: {
                    modules: ['login']
                }
            }
        },
        homePage: {
            path: '/',
            layout: 'basic',
            menuLabel: 'Home',
            title: 'Home page',
            description: 'Home page with login',
            regions: {
                main: {
                    modules: ['home']
                }
            }
        },
        test1: {
            path: '/test23',
            layout: 'basic',
            private: true,
            menuLabel: 'Test 1',
            title: 'Test 1',
            description: 'Test 1 page',
            regions: {
                main: {
                    modules: []
                },
            }
        },
    },
    settings: {}
};

export default config;
```

### DynamicModule

```jsx
import { DynamicModule } from "@react-app-composer/core";

const HeaderModule = () => {
    return (
        <div>
            <h1>Header title</h1>
            <DynamicModule name="Filters" somePropForModule="custom prop"/>
        </div>
    )
}

export default HeaderModule;
```
other example with create dynamic module instance
```jsx
import { createDynamicModule } from "@react-app-composer/core";

const FiltersModule = createDynamicModule('Filters');

const HeaderModule = () => {
    return (
        <div>
            <h1>Header title</h1>
            <FiltersModule somePropForModule="custom prop"/>
        </div>
    )
}

export default HeaderModule;
```


### DynamicComponent

```jsx
import { DynamicComponent } from "@react-app-composer/core";

const HeaderModule = () => {
    return (
        <div>
            <h1>Header title</h1>
            <DynamicComponent name="button" color="blue">Send messange</DynamicComponent>
        </div>
    )
}

export default HeaderModule;
```
other example with create dynamic component instance
```jsx
import { createDynamicComponent } from "@react-app-composer/core";
import DefaultButtonComponent from './components';

const Button = createDynamicComponent('button', DefaultButtonComponent);

const HeaderModule = () => {
    return (
        <div>
            <h1>Header title</h1>
            <Button color="blue">Send messange</Button>
        </div>
    )
}

export default HeaderModule;
```