apphouse v0.1.259
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>
);
});
18 days ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
9 months ago
10 months ago
9 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
9 months ago
10 months ago
9 months ago
9 months ago
9 months ago
10 months ago
9 months ago
10 months ago
9 months ago
10 months ago
9 months ago
10 months ago
9 months ago
9 months ago
10 months ago
9 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
11 months ago
11 months ago
11 months ago
11 months ago
11 months ago
11 months ago
11 months ago
11 months ago
11 months ago
11 months ago
11 months ago
11 months ago
11 months ago
11 months ago
11 months ago
11 months ago
11 months ago
11 months ago
11 months ago
11 months ago
11 months ago
11 months ago
11 months ago
11 months ago
11 months ago
11 months ago
11 months ago
11 months ago
11 months ago
11 months ago
11 months ago
11 months ago
11 months ago
11 months ago
11 months ago
11 months ago
11 months ago
11 months ago
11 months ago
11 months ago
11 months ago
11 months ago
11 months ago
11 months ago
11 months ago
11 months ago
11 months ago
11 months ago
11 months ago
11 months ago
11 months ago
11 months ago
11 months ago
11 months ago
11 months ago
11 months ago
11 months ago