apphouse
v0.1.260
Published
Component library for React that uses observable state management and theme-able components.
Downloads
30
Readme
Apphouse
** THIS LIBRARY IS UNDER DEVELOPMENT - API MIGHT CHANGE SIGNIFICANTLY **
- A highly efficient method for creating a React + Typescript application.
- Comprehensive reusable components that can look completely different based on a configurable theme
- Models that support observability for faster and more efficient rendering
Why Apphouse?
- Apphouse simplifies the pain of writing themes, forms, popups, routes, feedback, etc., providing a comprehensive solution for all these essential components that you always need. Although it can handle a lot, using Apphouse is incredibly easy and user-friendly.
Usage
Via CLI
With our cli app, you can effortlessly start an entire project in just two simple commands.
Note: You must use node v18.0.0 nvm use v18.0.0
npm install -g apphouse-cli
apphouse-cli your-project-name
Manually
npm install apphouse
Sample App
Initialize Apphouse
import React from 'react';
import ReactDOM from 'react-dom/client';
import { initApphouse } from 'apphouse';
const store = initApphouse(routes);
ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
<ApphouseApp store={store} />
);
Setting Up Routes
To define specific routes for your app, simple create a route object and use it when initializing apphouse
import React from 'react';
import ReactDOM from 'react-dom/client';
import { initApphouse, ApphouseApp } from 'apphouse';
const routes: Route[] = [
{
path: '/',
title: 'Home',
component: () => {
return <App />;
}
}
];
const store = initApphouse(routes);
ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
<ApphouseApp store={store} />
);
Setting Up Restricted Routes
To define a restricted route, simply wrap it with RequiresFirebaseAuthentication component. We currently only support firebase simple email & password authentication.
import React from 'react';
import ReactDOM from 'react-dom/client';
import { initApphouse } from 'apphouse';
const routes: Route[] = [
{
path: '/',
title: 'Home',
component: () => {
return <App />;
}
},
{
path: '/account',
title: 'Account',
component: (
<RequiresFirebaseAuthentication showSignInButton showSignOutButton>
<MySecretContentComponent />
</RequiresFirebaseAuthentication>
)
}
];
const firebaseConfig = {
apiKey: 'yourApiKey',
authDomain: 'yourAuthDomain',
projectId: 'yourProjectId',
storageBucket: 'yourStorageBucket',
messagingSenderId: 'yourMessagingSenderId',
appId: 'yourAppId',
measurementId: 'yourmeasurementId'
};
const appStore = new AppStoreWithUser(firebaseConfig);
const store = initApphouse(
Routes,
appStore as IStoreWithBase<AppStoreWithUser>
);
ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
<ApphouseApp store={store} />
);
Setting Up Routes With Params
We also accept parametrized routing
import React from 'react';
import ReactDOM from 'react-dom/client';
import { initApphouse } from 'apphouse';
const routes: Route[] = [
{
path: '/account/:id',
title: 'My Account',
component: ({ id }) => <MyComponentForPage1 id={id} />
}
];
const store = initApphouse(routes);
ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
<ApphouseApp store={store} />
);
Extending Theme
You can change your app theme simply by extending apphouse's default theme or making your own from scratch
Extending Theme
const BRAND_COLOR = 'rgb(236, 0, 138)';
const customTheme: ApphouseTheme = extendTheme(DarkTheme, {
colors: {
brand: BRAND_COLOR
},
tokens: {
radius: {
default: '30px'
}
},
styles: {
input: {
default: {
borderRadius: '30px'
}
}
}
});
const store = initApphouse(routes);
ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
<ApphouseApp store={store} theme={customTheme} />
);
Check out our demo app to get a sneak peek at how you can easily customize your theme. Simply visit this link to explore and experiment with various customization options.
Personalized Not Found Page
Every time a user tries to access a route that doesn't exist, they will be redirected to this page. By default Apphouse offers a standard 404 Not Found page. If you want to overwrite this page with your own 404 page add your 404 substitute when defining the route
const routes: Route[] = [
{
path: '/404',
title: 'Not Found',
component: () => <MyCustom404Page />
}
];
Handling Alerts
Anywhere inside of your components you can fire the feedback by calling the alert method
const { alert } = useApphouse();
alert({
type: FeedbackType.success,
message: 'Success message',
duration: 3000
});
Handling Forms
Apphouse provides a simple and efficient way to handle very complex forms. To create a form, simply create a new instance of Form class and pass in the form configuration object.
const form = new Form({
id: "signUp", // you will use this id to retrieve this form later
title: 'Sign Up!',
fields: {
// initial value for this field can be set here
name: "",
// initial value for this field can be set here
email: ""
},
validations: {
email: (value: string) => {
// do email validation
return true if valid, return false if invalid
}
},
options: {}, // no options
required: ['name', 'email'], // both name and email fields are required
Updating Values
To update form field value simply:
form.setValue('name', 'updatedName');
Accessing form values
const name = form.getValue('name');
Get all form data
To get current form data
const formData = form.data;
For more detailed information on how to use the form view the form documentation
Using the ApphouseForm Component
If you just want to create a simple form, you can use the ApphouseForm component.
Below is an example that showcases the usage of ApphouseForm component along with the Popup component to create a prompt that asks the user to enter a file name.
import { ApphouseForm } from '../components/Form/ApphouseForm';
import { Popup } from '../components/popup/Popup';
/**
* A prompt that will ask the user to enter a file name
*/
export const PromptFilename = ApphouseComponent((props: { onConfirm }) => {
const { onConfirm } = props;
const onSubmission = (formData) => {
onConfirm(formData.filename);
};
return (
<Popup
id="PromptFilenamePopup"
title="Save theme as"
closeOnClickOutside
hideFooterActions
showCloseButton
width="320px"
gutters={4}
>
<ApphouseForm
id="PromptFilenameForm"
fields={[
{
id: 'filename',
label: 'File name',
type: 'text',
required: true,
value: undefined,
styleOverwrites: {
container: {
width: '100%'
},
input: {
width: '100%'
}
}
}
]}
submitButtonLabel="Save"
onSubmission={onSubmission}
/>
</Popup>
);
});
Registering Shortcuts
Apphouse can handle shortcuts anywhere in the app. You can register a global shortcut by:
app.shortcuts.register('escape', callback);
Similarly you can unregister a global shortcut by
app.shortcuts.unregister('escape', callback);
If you want to register multiple shortcuts you can do so by using the registerAppShortcuts
method
app.shortcuts.registerAppShortcuts([
{
combo: 'cmd+s',
action: () => {
console.log('save');
}
}
]);
Shortcut in Text fields
By default all keyboard events will not fire if you are inside of a textarea, input, or select to prevent undesirable things from happening.
Partial Views
A partial view refers to any view within the application that does not take up the entire page or is considered "transient" within a flow. Examples of partial views include modals, tabs, popups, pickers, and so on.
There are several scenarios in which you would want to set a partial view:
- When you want to provide the option for users to quickly close the view by using the 'escape' shortcut.
- When you want to enable users to access the view via a specific URL.
- When you want to allow the opening and closing of the view through a trigger located in a completely different place from where the view will be displayed.
// set up route in routes and set openPartial: true
{
path: '/demo/:themeEditor',
title: 'Theme Editor Drawer Open',
openPartial: true,
component: () => {
return <Demo />;
}
}
export const DrawerDemo = observer(() => {
const { app } = useApphouse();
const { view } = app;
return (
<React.Fragment>
<div>
<Button
onClick={() => {
// this will open the drawer below and also update the url
// to be demo/themeEditor
view.setView('themeEditor', true);
}}
>
Edit theme
</Button>
</div>
<Drawer
id="theme-editor"
open={view.getViewStatus('themeEditor')}
onClose={() => view.setView('themeEditor', false)}
>
drawer content
</Drawer>
</React.Fragment>
);
});