@webbyx/mui v0.0.24
@webbyx/mui
This objective of this package is to help developer to ease the development & deliver application in shorter time
Table of Content
Installation
yarn add @webbyx/mui
# other dependencies
yarn add @mui/material @mui/icons-material @emotion/react @emotion/server @emotion/styled @iconify/react next-translate react-perfect-scrollbar react-use stylis stylis-plugin-rtl animate.css
Getting Started
Extend Module
// file: next.d.ts
import type { ReactElement, ReactNode } from 'react';
import { ThemeSettings } from '@webbyx/mui';
import type { NextComponentType, NextPageContext } from 'next/dist/shared/lib/utils';
declare module 'next' {
export declare type NextPage<P = any, IP = P> = NextComponentType<NextPageContext, IP, P> & {
setPageThemeSettings?: () => ThemeSettings;
getLayout?: (page: ReactElement) => ReactNode;
};
}
Custom Application
// file: src/pages/_app.tsx
import type { EmotionCache } from '@emotion/cache';
import { CacheProvider } from '@emotion/react';
import { createEmotionCache, LayoutConfigProvider } from '@webbyx/mui';
import { NextPage } from 'next';
import { AppProps } from 'next/app';
import Head from 'next/head';
import Layout from '../config/layout.config';
import { useThemeConfig } from '../config/theme.config';
import 'animate.css';
import 'react-perfect-scrollbar/dist/css/styles.css';
type ExtendedAppProps = AppProps & {
Component: NextPage;
emotionCache: EmotionCache;
};
const clientSideCache = createEmotionCache();
function CustomApp(props: ExtendedAppProps) {
const { Component, emotionCache = clientSideCache, pageProps } = props;
const config = useThemeConfig();
const router = props.router;
const setPageThemeSettings = Component.setPageThemeSettings ?? undefined;
return (
<CacheProvider value={emotionCache}>
<Head>
<title>Welcome to example!</title>
</Head>
<LayoutConfigProvider
config={config}
paths={[router.asPath, router.pathname]}
pageSettings={setPageThemeSettings?.()}
/**
* [OPTIONAl]
* to set/read theme settings from your preferred storage, eg: SessionStorage, Cookie, etc
* NOTE: if not defined will auto fallback to LocalStorage
*/
storage={{
set: (settings) => {
//
nookies.setCookie(props.pageProps, 'settings', settings, {
maxAge: 3000 * 24 * 60 * 60,
});
},
get: () => {
const cookies = nookies.parseCookies(props.pageProps || {});
return cookies['settings'];
},
}}
// to customize loader
loader={{
// override the loader lasting time
lasting: 1000,
// the speed of animation
speed: 'fast',
// the animation type
animation: 'jello',
// the custom brand
brand: (
<div className="logo-container" style={{ width: 100, height: 100 }}>
<svg fill="currentColor" role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path d="M11.987 14.138l-3.132 4.923-5.193-8.427-.012 8.822H0V4.544h3.691l5.247 8.833.005-3.998 3.044 4.759zm.601-5.761c.024-.048 0-3.784.008-3.833h-3.65c.002.059-.005 3.776-.003 3.833h3.645zm5.634 4.134a2.061 2.061 0 0 0-1.969 1.336 1.963 1.963 0 0 1 2.343-.739c.396.161.917.422 1.33.283a2.1 2.1 0 0 0-1.704-.88zm3.39 1.061c-.375-.13-.8-.277-1.109-.681-.06-.08-.116-.17-.176-.265a2.143 2.143 0 0 0-.533-.642c-.294-.216-.68-.322-1.18-.322a2.482 2.482 0 0 0-2.294 1.536 2.325 2.325 0 0 1 4.002.388.75.75 0 0 0 .836.334c.493-.105.46.36 1.203.518v-.133c-.003-.446-.246-.55-.75-.733zm2.024 1.266a.723.723 0 0 0 .347-.638c-.01-2.957-2.41-5.487-5.37-5.487a5.364 5.364 0 0 0-4.487 2.418c-.01-.026-1.522-2.39-1.538-2.418H8.943l3.463 5.423-3.379 5.32h3.54l1.54-2.366 1.568 2.366h3.541l-3.21-5.052a.7.7 0 0 1-.084-.32 2.69 2.69 0 0 1 2.69-2.691h.001c1.488 0 1.736.89 2.057 1.308.634.826 1.9.464 1.9 1.541a.707.707 0 0 0 1.066.596zm.35.133c-.173.372-.56.338-.755.639-.176.271.114.412.114.412s.337.156.538-.311c.104-.231.14-.488.103-.74z" />
</svg>
</div>
),
}}
>
<Layout>
<Component {...pageProps} />
</Layout>
</LayoutConfigProvider>
</CacheProvider>
);
}
export default CustomApp;
Custom Document
// file: src/pages/_document.tsx
import { Children } from 'react';
import createEmotionServer from '@emotion/server/create-instance';
import { createEmotionCache } from '@webbyx/mui';
import Document, { DocumentContext, DocumentInitialProps, Head, Html, Main, NextScript } from 'next/document';
export default class CustomDocument extends Document {
static async getInitialProps(ctx: DocumentContext): Promise<DocumentInitialProps> {
const originalRenderPage = ctx.renderPage;
const cache = createEmotionCache();
const { extractCriticalToChunks } = createEmotionServer(cache);
ctx.renderPage = () =>
originalRenderPage({
enhanceApp: (App) => (props) => <App {...props} emotionCache={cache} />,
});
const initialProps = await Document.getInitialProps(ctx);
const emotionStyles = extractCriticalToChunks(initialProps.html);
const emotionStyleTags = emotionStyles.styles.map((style) => {
return <style key={style.key} dangerouslySetInnerHTML={{ __html: style.css }} data-emotion={`${style.key} ${style.ids.join(' ')}`} />;
});
return {
...initialProps,
styles: [...Children.toArray(initialProps.styles), ...emotionStyleTags],
};
}
render() {
return (
<Html>
<Head>{this.props.styles}</Head>
<body>
<Main />
<NextScript />
</body>
</Html>
);
}
}
Add Theme Config
Configure theme config & setting for your layout.
// file: src/config/theme.config.ts
import { ThemeConfig } from '@webbyx/mui';
export const useThemeConfig = (): ThemeConfig => {
return {
settings: {
mode: 'dark', // dark mode
skin: 'default',
},
// overriding theme with function
overrides: {
palette: {
primary: {
light: '#5A5FE0',
main: '#5A5FE0',
dark: '#5A5FC1',
contrastText: '#fff',
},
},
spacing: (factor: number) => {
return `${0.2 * factor}rem`;
},
components: {},
},
// menuTextTruncate: true,
enableCustomizer: true,
// responsiveFontSizes: true,
};
};
Add Layout config
Below were example of how to apply layout for your application
// file: src/config/layout.config.tsx
import CircleIcon from '@mui/icons-material/Circle';
import GridViewIcon from '@mui/icons-material/GridView';
import LogoutIcon from '@mui/icons-material/Logout';
import PeopleIcon from '@mui/icons-material/People';
import SettingsOutlinedIcon from '@mui/icons-material/SettingsOutlined';
import React, { ReactNode } from 'react';
import { MainLayout } from '@webbyx/mui';
export type LayoutProps = {
children: ReactNode;
contentHeightFixed?: boolean;
};
export const Layout: React.FC<LayoutProps> = (props) => {
const { contentHeightFixed, children } = props;
// ======================= VIEWS
return (
<MainLayout
name="Webby"
company="Webby Sdn Bhd"
brandingLink="/dashboard"
enableFixedContentHeight={contentHeightFixed}
verticalLayoutProps={{
navigation: {
items: [
{
key: 'dashboard',
title: 'Dashboard',
icon: <GridViewIcon />,
path: '/dashboard',
},
{
type: 'group',
key: 'customer',
title: 'Customer',
icon: <PeopleIcon />,
children: [
{
key: 'application-listing',
title: 'Application Listing',
icon: <CircleIcon sx={{ fontSize: 6 }} />,
path: '/customer/application',
includes: ['/customer/application/[id]', '/customer/application/[id]/questionnaire'],
badge: {
color: 'error',
content: 1,
},
},
{
key: 'customer-listing',
title: 'Customer Listing',
icon: <CircleIcon sx={{ fontSize: 6 }} />,
path: '/customer',
includes: ['/customer/[id]', '/customer/[id]/questionnaire'],
},
],
},
],
},
appBar: {
rightItems: [
{ type: 'mode' },
{ type: 'language' },
{
type: 'user',
props: {
name: 'John Doe',
role: 'Admin',
color: 'primary',
},
items: [
{
key: 'settings',
title: 'Settings',
url: '/settings',
icon: <SettingsOutlinedIcon />,
},
'divider',
{
key: 'logout',
title: 'Logout',
icon: <LogoutIcon />,
onClick: () => {
console.log('clicked logout!');
},
},
],
},
],
},
}}
>
{children}
</MainLayout>
);
};
// ======================= EXPORT
export default Layout;
Reference
Theme Config
type ThemeConfig = {
/**
* the layout theme settings
*/
settings?: ThemeSettings;
/**
* the options that used to override mui/layout theme
*/
overrides?: ((mode: Mode, skin: Skin, config?: ThemeConfig) => ThemeOptions) | ThemeOptions;
/**
* Number in px(Pixels)
* Note: This is for Vertical navigation menu only
* default `260`
*/
navigationWidth?: number;
/**
* iconify icon type for navigation header
* this will be applied if Layout doesn't provide branding
* refer https://icon-sets.iconify.design/ for more icons
* default `solar:home-2-bold`
*/
navHeaderIcon?: string;
/**
* iconify icon type for navigation submenu
* refer https://icon-sets.iconify.design/ for more icons
* default `mdi:circle`
*/
navSubItemIcon?: string;
/**
* whether to show icon for submenu,
* default `true`
*/
enableSubItemIcon?: boolean;
/**
* whether to truncate text for menu item if text was too long
* default `true`
*/
menuTextTruncate?: boolean;
/**
* Number in px(Pixels)
* Note: This is for Vertical navigation menu only
* default `68`
*/
navigationCollapsedWidth?: number;
/**
* whether to have menu animation
* NOTE: only applied to horizontal layout
* default `true`
*/
horizontalMenuAnimation?: boolean;
/**
* content display position within navigation,
* default `fixed`
*/
afterVerticalNavMenuContentPosition?: 'fixed' | 'static';
/**
* content display position within navigation
* default `fixed`
*/
beforeVerticalNavMenuContentPosition?: 'fixed' | 'static';
/**
* whether to disable ripple effect
* default `false`
*/
disableRipple?: boolean;
/**
* whether to show theme customizer
* default `false`
*/
enableCustomizer?: boolean;
/**
* whether to have responsive font size
* default `true`
*/
responsiveFontSizes?: boolean;
/**
* whether to enable preset toaster styles
* default `true`
*/
enablePresetToaster?: boolean;
/**
* whether to have unstyled components (this package comes preset component styles for mui theme)
* default `false`
*/
enableUnstyledComponent?: boolean;
/**
* whether to have unstyled breakpoints (this package comes preset breakpoint for mui theme)
* default `false`
*/
enableUnstyledBreakpoint?: boolean;
/**
* whether to have unstyled typography (this package comes preset typography for mui theme)
* default `false`
*/
enableUnstyledTypography?: boolean;
/**
* whether to have unstyled shadows (this package comes preset shadows for mui theme)
* default `false`
*/
enableUnstyledShadows?: boolean;
/**
* whether to have unstyled shape (this package comes preset shape for mui theme)
* default `false`
*/
enableUnstyleShape?: boolean;
/**
* whether to have unstyled spacing (this package comes preset spacing for mui theme)
* default `false`
*/
enableUnstyleSpacing?: boolean;
/**
* whether to have unstyled mixins (this package comes preset mixins for mui theme)
* default `false`
*/
enableUnstyleMixins?: boolean;
/**
* ADDED on v0.0.14
* whether to exclude components styles (this package comes preset component styles for mui theme)
* NOTE: do note that when `enableUnstyledComponent` set to true
* all component styles not defined in this props all will be excluded
* default `[]`
*/
excludeComponentStyles?: ComponentStyleType[];
/**
* ADDED on v0.0.20
* whether to show loader over the screen on initial website load
* default `false`
*/
enableLayoutLoader?: boolean;
/**
* ADDED on v0.0.20
* justify the lasting time in milliseconds for the loader to be visible
* default: 2000
*/
layoutLoaderLasting?: number;
/**
* ADDED on v0.0.20
* layout loader view animation speed type
* default: `slower`
*/
layoutLoaderSpeed?: LoaderSpeedType;
/**
* ADDED on v0.0.20
* layout loader view animation type
* default: `none`
*/
layoutLoaderAnimation?: LoaderAnimationType;
};
Theme Settings
import { PaletteMode } from '@mui/material';
type LayoutType = 'vertical' | 'horizontal';
type Skin = 'default' | 'bordered';
type Mode = PaletteMode | 'semi-dark';
type ContentWidth = 'full' | 'boxed';
type AppBarType = 'fixed' | 'static' | 'hidden';
type FooterType = 'fixed' | 'static' | 'hidden';
type ThemeColor = 'primary' | 'secondary' | 'error' | 'warning' | 'info' | 'success';
type VerticalNavToggle = 'accordion' | 'collapse';
type HorizontalMenuToggle = 'hover' | 'click';
type ToastPositionType = 'top-left' | 'top-center' | 'top-right' | 'bottom-left' | 'bottom-center' | 'bottom-right';
type ComponentStyleType = 'accordion' | 'alert' | 'autocomplete' | 'avatar' | 'backdrop' | 'breadcrumb' | 'button-group' | 'button' | 'card' | 'chip' | 'data-grid' | 'dialog' | 'divider' | 'fab' | 'input' | 'link' | 'list' | 'menu' | 'pagination' | 'paper' | 'popover' | 'progress' | 'rating' | 'select' | 'snackbar' | 'switch' | 'table' | 'tabs' | 'timeline' | 'toggle-button' | 'tooltip' | 'typography';
type LoaderSpeedType = 'slow' | 'slower' | 'fast' | 'faster';
type LoaderAnimationType = 'none' | 'bounce' | 'flash' | 'rubberBand' | 'shakeX' | 'shakeY' | 'headShake' | 'swing' | 'tada' | 'wobble' | 'jello' | 'heartBeat';
type ThemeSettings = {
/**
* ===============================
* GENERAL
* ===============================
*/
/**
* default | bordered
*/
skin?: Skin;
/**
* light | dark | semi-dark
* Note: semi-dark value will only work for Vertical Layout
*/
mode?: Mode;
/**
* The primary color to display on theme
*/
themeColor?: ThemeColor;
/**
* ===============================
* LAYOUT
* ===============================
*/
/**
* the layout type
* default `vertical`
*/
layout?: LayoutType;
/**
* The direction of the layout
* default `ltr`
*/
direction?: Direction;
/**
* display content size
* `full` : full width
* `boxed` : boxed width
* default `boxed`
*/
contentWidth?: ContentWidth;
/**
* `accordion` : collapse one another
* `collapse` : each nav is
* Note: This is for Vertical navigation menu only
* default `collapse`
*/
verticalNavToggleType?: VerticalNavToggle;
/**
* open menu on `click` | `hover`
* Note: This is for Horizontal navigation menu only
*/
horizontalMenuToggle?: HorizontalMenuToggle;
/**
* ===============================
* APP BAR
* ===============================
*/
/**
* fixed | static | hidden
* Note: hidden value will only work for Vertical Layout
*/
appBar?: AppBarType;
/**
* whether to have blur-ish app bar
*/
appBarBlur?: boolean;
/**
* ===============================
* FOOTER
* ===============================
*/
/**
* The footer display types
* fixed : always fixed position at bottom
* static : static footer
* hidden : hidden footer
*/
footer?: FooterType;
/**
* ===============================
* NAVIGATION
* ===============================
*/
/**
* whether to hide navigation
*/
navHidden?: boolean; // navigation menu
/**
* collapsed the navigation
* Note: This is for Vertical navigation menu only
*/
navCollapsed?: boolean;
/**
* toast display position
*/
toastPosition?: ToastPositionType;
};
Default Theme Config
This package has comes with default config and below were the configuration
Config | Function | Link |
---|---|---|
breakpoints | createThemeOverrideConfigBreakpoints | link |
mixins | createThemeOverrideConfigMixins | link |
palette | createThemeOverrideConfigPalette | link |
shadows | createThemeOverrideConfigShadows | link |
shape | createThemeOverrideConfigShape | link |
spacing | createThemeOverrideConfigSpacing | link |
typography | createThemeOverrideConfigTypography | link |
Available Component Styles
This package has comes with list of component styles by default. Do checkout the list below for more detail
Component | Function | Link |
---|---|---|
accordion | createThemeOverrideAccordion | link |
alert | createThemeOverrideAlert | link |
autocomplete | createThemeOverrideAutocomplete | link |
avatar | createThemeOverrideAvatar | link |
backdrop | createThemeOverrideBackdrop | link |
breadcrumb | createThemeOverrideBreadcrumb | link |
button | createThemeOverrideButton | link |
button-group | createThemeOverrideButtonGroup | link |
card | createThemeOverrideCard | link |
chip | createThemeOverrideChip | link |
data-grid | createThemeOverrideDataGrid | link |
dialog | createThemeOverrideDialog | link |
divider | createThemeOverrideDivider | link |
fab | createThemeOverrideFab | link |
input | createThemeOverrideInput | link |
link | createThemeOverrideLink | link |
list | createThemeOverrideList | link |
menu | createThemeOverrideMenu | link |
pagination | createThemeOverridePagination | link |
paper | createThemeOverridePaper | link |
popover | createThemeOverridePopover | link |
progress | createThemeOverrideProgress | link |
rating | createThemeOverrideRating | link |
select | createThemeOverrideSelect | link |
snackbar | createThemeOverrideSnackbar | link |
switch | createThemeOverrideSwitch | link |
table | createThemeOverrideTable | link |
tabs | createThemeOverrideTabs | link |
timeline | createThemeOverrideTimeline | link |
toggle-button | createThemeOverrideToggleButtonGroup | link |
tooltip | createThemeOverrideTooltip | link |
typography | createThemeOverrideTypography | link |
Guide
Module Augmentation
To understand & to add new variables to the ThemeOptions
can always refer module augmentation from mui official website.
This package has comes with custom colors on palette, and below is original configuration
declare module '@mui/material/styles' {
interface Palette {
customColors: {
dark: string;
main: string;
light: string;
bodyBg: string;
darkBg: string;
lightBg: string;
trackBg: string;
avatarBg: string;
tooltipBg: string;
tableHeaderBg: string;
avatarText: string;
accent: string;
};
}
interface PaletteOptions {
customColors?: {
dark?: string;
main?: string;
light?: string;
bodyBg?: string;
darkBg?: string;
lightBg?: string;
trackBg?: string;
avatarBg?: string;
tooltipBg?: string;
tableHeaderBg?: string;
avatarText?: string;
accent?: string;
};
}
}
If you wish to have your custom colors, can extend the original configuration like below
// file : typings.d.ts (example)
declare module '@mui/material/styles' {
interface Palette {
customColors: {
dark: string;
main: string;
light: string;
bodyBg: string;
darkBg: string;
lightBg: string;
trackBg: string;
avatarBg: string;
tooltipBg: string;
tableHeaderBg: string;
avatarText: string;
accent: string;
myFavoriteColor: string; // <-- added this
};
}
interface PaletteOptions {
customColors?: {
dark?: string;
main?: string;
light?: string;
bodyBg?: string;
darkBg?: string;
lightBg?: string;
trackBg?: string;
avatarBg?: string;
tooltipBg?: string;
tableHeaderBg?: string;
avatarText?: string;
accent?: string;
myFavoriteColor?: string; // <-- added this
};
}
}
NOTE: Do remember that if your TypeScript configuration isn't picking up the
typings.d.ts
file by default, you might have to adjust theinclude
ortypes
fields in yourtsconfig.json
.
Mix & Match Component Styles
By default, the package has comes with all components styles applied.
If you wish to pick your preferred component styles, you can import the override function according to available component styles
// file: src/config/theme.config.ts (example)
import { createThemeOverrideAvatar, createThemeOverrideTypography, ThemeConfig } from '@webbyx/mui';
export const useThemeConfig = (): ThemeConfig => {
return {
settings: {},
overrides: (mode, skin, config) => {
return {
components: {
...createThemeOverrideAvatar(mode, skin, config),
...createThemeOverrideTypography(mode, skin, config),
},
};
},
enableUnstyledComponent: true, // you wants unstyled components
};
};
Exclude component styles
If you wish to exclude certain component styles, you can use excludeComponentStyles
to specified which component do you wants to exclude. Do checkout available component styles
// file: src/config/theme.config.ts (example)
import { ThemeConfig } from '@webbyx/mui';
export const useThemeConfig = (): ThemeConfig => {
return {
excludeComponentStyles: ['accordion', 'button', 'menu'],
};
};
Loader visibility
This package has comes with loader, below is the default configuration in theme config, you may overwrite it with your theme config
enableLayoutLoader: false,
layoutLoaderLasting: 2000,
layoutLoaderSpeed: 'slower',
layoutLoaderAnimation: 'none'
To manually control the loader visibility, can use useLayoutLoader
import { useLayoutLoader } from '@webbyx/mui';
export function Index() {
// use the layout loader hook
const { setVisibility, show, hide, promise } = useLayoutLoader();
return (
<div>
<Button onClick={() => show()}>Show loader</Button>
<br />
<Button onClick={() => hide()}>Hide loader</Button>
<br />
<Button onClick={() => setVisibility()}>Toggle loader</Button>
<br />
<Button
onClick={() => {
promise(new Promise((r) => setTimeout(r, 5000)));
}}
>
Promise loader
</Button>
</div>
);
}
7 months ago
7 months ago
7 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago