0.0.24 • Published 7 months ago

@webbyx/mui v0.0.24

Weekly downloads
-
License
-
Repository
-
Last release
7 months ago

@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

ConfigFunctionLink
breakpointscreateThemeOverrideConfigBreakpointslink
mixinscreateThemeOverrideConfigMixinslink
palettecreateThemeOverrideConfigPalettelink
shadowscreateThemeOverrideConfigShadowslink
shapecreateThemeOverrideConfigShapelink
spacingcreateThemeOverrideConfigSpacinglink
typographycreateThemeOverrideConfigTypographylink

Available Component Styles

This package has comes with list of component styles by default. Do checkout the list below for more detail

ComponentFunctionLink
accordioncreateThemeOverrideAccordionlink
alertcreateThemeOverrideAlertlink
autocompletecreateThemeOverrideAutocompletelink
avatarcreateThemeOverrideAvatarlink
backdropcreateThemeOverrideBackdroplink
breadcrumbcreateThemeOverrideBreadcrumblink
buttoncreateThemeOverrideButtonlink
button-groupcreateThemeOverrideButtonGrouplink
cardcreateThemeOverrideCardlink
chipcreateThemeOverrideChiplink
data-gridcreateThemeOverrideDataGridlink
dialogcreateThemeOverrideDialoglink
dividercreateThemeOverrideDividerlink
fabcreateThemeOverrideFablink
inputcreateThemeOverrideInputlink
linkcreateThemeOverrideLinklink
listcreateThemeOverrideListlink
menucreateThemeOverrideMenulink
paginationcreateThemeOverridePaginationlink
papercreateThemeOverridePaperlink
popovercreateThemeOverridePopoverlink
progresscreateThemeOverrideProgresslink
ratingcreateThemeOverrideRatinglink
selectcreateThemeOverrideSelectlink
snackbarcreateThemeOverrideSnackbarlink
switchcreateThemeOverrideSwitchlink
tablecreateThemeOverrideTablelink
tabscreateThemeOverrideTabslink
timelinecreateThemeOverrideTimelinelink
toggle-buttoncreateThemeOverrideToggleButtonGrouplink
tooltipcreateThemeOverrideTooltiplink
typographycreateThemeOverrideTypographylink

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 the include or types fields in your tsconfig.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>
  );
}
0.0.24

7 months ago

0.0.23

7 months ago

0.0.22

7 months ago

0.0.21

8 months ago

0.0.20

8 months ago

0.0.19

8 months ago

0.0.18

8 months ago

0.0.17

8 months ago

0.0.16

8 months ago

0.0.15

8 months ago

0.0.14

8 months ago

0.0.13

9 months ago

0.0.12

9 months ago

0.0.11

9 months ago

0.0.10

9 months ago

0.0.9

9 months ago

0.0.8

9 months ago

0.0.7

9 months ago

0.0.6

9 months ago

0.0.5

9 months ago

0.0.4

9 months ago

0.0.3

9 months ago

0.0.2

9 months ago

0.0.1

9 months ago

0.1.0

9 months ago

0.0.0

9 months ago