Giter Site home page Giter Site logo

bigyanpoudel / react-global-modal Goto Github PK

View Code? Open in Web Editor NEW
5.0 1.0 1.0 305 KB

Use modal in any component with in the application without any pain ๐Ÿ˜ญ

Home Page: https://react-global-modal.vercel.app

License: MIT License

Shell 0.08% HTML 2.55% CSS 5.43% TypeScript 88.74% JavaScript 2.54% SCSS 0.66%
react-modal react-global-modal modal modal-dialogs modals react

react-global-modal's Introduction

React Global Modal

React Global Modal is a lightweight, simple, customizable and ready to use modal in the global scope in the react project.

npm version npm downloads npm bundle size

Features

  • Lightweight
  • Build in simple modal, slide pane, confirmation modal and async confirmation modal
  • Fully constomizable and can be used with any UI framework
  • Invoked as a method so reduces the code base
  • Promotes reusability
  • Easy to maintain
  • Enhance the performance as the main component never re-render when opening the modal
  • Multiple modal can be pushed on top of another

Table of Contents

Installation

To install, you can use npm or yarn:

$ npm install react-global-modal
$ yarn add react-global-modal

Usage

In order to use, you must follow the steps below:

1. Configure React Global Modal

At first, you need to configure the modal at the root of your project as shown bellow

import React, { useEffect } from 'react'
import { GlobalModalWrapper, GlobalModal } from 'react-global-modal'
import 'react-global-modal/dist/style.css'

let globalModalRef: any = null

function App() {
  useEffect(() => {
    GlobalModal.setUpModal(globalModalRef)
  }, [])

  return (
    <div className="App">
      <GlobalModalWrapper ref={(el) => (globalModalRef = el)} />
    </div>
  )
}

export default App

Here GlobalModal.setUpModal methods register our modal by storing the reference of the modal obtained from the GlobalModalWrapper. react-global-modal/dist/style.css is the styles of the modal which you also need to import in the root file of the project.

2. Triggering exposed modal methods

The GlobalModal consist of set method using which we can open and close the modal and also can update the props passed to the modal. It consist of following methods:

1. setUpModal
2. push
3. pop
4. add
5. closeAll
1. setUpModal

You can use this method to register the modal reference and should be defined in the root of the project as mention above in Configure React Global Modal

2. push

You can use this method to open the modal which conatin a list of props along with the component that we want to display inside the modal.

  const openModal = async () => {
    GlobalModal.push({
      component:Component, //Component represent the component that you want to display inside the modal
      title:"Modal title" //modal title
      props:{   //props object are represented as the props to the component
        data:data   
      }
    })
  }

The methods contain different others properties which are described below:

Props Types Required Default Description
component React.FC โœ… Main component that will be displayed inside modal
props { [key: string]: unknown } It include the props of the component which can be accessed inside the modal
onClose Function Is used to perfrom certain action when the modal is about to close
className string It is used to provde the styles for outermost element of the modal and can be used accordingly with custom modal
modalSize 'xs' , 'sm' ,'md' , 'lg' โœ… md It is used to control the width of the modal
isCloseable boolean false It indicate wheather the modal can be closed or not. If true, you can only close the modal manualy from the component inside the modal using the modal close method
closeButtonClassName string It is used to style the close icon that is present inside the modal
title string If you want to have a title in the modal you can use it.
hideHeader boolean false It is used to hide the deafult heading component present in the modal
headerComponent React.FC You can pass the custom heading component in the modal
headerClassName string It is used to style the heading the component
actions IButtonProps[] It includes the list of button that can be included in the bottom of the modal
actionClassName string It is used to style the footer of the component
contentClassName string It is used to style the wrapper which wraps the passed component to the modal
hideCloseIcon boolean It is used to hide the close icon from the modal
width string It is used to include the custom width to the modal
isSlidePane boolean false If it is true, then the modal will act as the slidePane and will be in right or left
position 'right' , 'left' right It can only be used when the isSlidePane is true. Using this you can align the slidPane to right or left
footer React.ReactNode You can pass custom footer to the modal
closeIconComponent React.ReactNode You can pass custom footer to the modal
3. pop

You can use this method to close the modal. In order to simply close the modal you can use like below:

    GlobalModal.pop()

4. add

You can use this method for updating any props values inside the modal. And this can be triggered from outside the modal as well as inside the modal

 GlobalModal.add({
      props: {       // this is the updated props which will be passed to the component inside the modal
        value: newValue, 
      },
      modalIndex: 0,  // it indicate current number of modal open
 })

In above method, modalIndex represents the index of opened modal. If you have one modal opened, then modalIndex will be 0 else if you have second modal opened on top of first one then themodalIndex will be 1 and soon.

5. closeAll

You can use this method to close all the modal that are opened. In order to simply close all the modal that you have opened previously you can use like below:

    GlobalModal.closeAll()

Examples

1. Simple example with in built header and no footer

const Example = () => {
  const openModal = async () => {
    GlobalModal.push({
      component: ComponentText,
      props: {
        test: 'Testing',
      },
    })
  }

  return (
    <div>
      <button onClick={openModal}>Open</button>
    </div>
  )
}
const ComponentText = ({ test }: { test: string }) => {
  return (
    <div
      style={{
        height: '400px',
      }}
    >
      hello {test}
    </div>
  )
}
export default Example

2. Simple example with header and footer inside component

import React from 'react'
import { GlobalModal } from 'react-global-modal'

const Example = () => {
  const openModal = async () => {
    GlobalModal.push({
      component: ComponentText,
      props: {
        test: 'Testing',
      },
      hideHeader: true,
    })
  }

  return (
    <div>
      <button onClick={openModal}>Open</button>
    </div>
  )
}
const ComponentText = ({ test }: { test: string }) => {
  return (
    <div
      style={{
        height: '400px',
      }}
    >
      <div
        style={{
          height: '2rem',
        }}
      >
        Header
      </div>
      hello {test}
      <div
        style={{
          position: 'absolute',
          left: 0,
          bottom: 0,
          width: '100%',
          borderTop: '1px solid rgb(230 232 240)',
        }}
      >
        <div
          style={{
            display: 'flex',
            flexDirection: 'row',
            padding: '8px 10px',
            justifyContent: 'flex-end',
            gridGap: '5px',
          }}
        >
          <button className="btn btn-error">Close</button>
          <button className="btn btn-primary"> okay</button>
        </div>
      </div>
    </div>
  )
}
export default Example

You can also include the header and footer in the component which will by displayed inside the modal but you have to disable the header present inside the modal by passing the props hideHeader: true

Modal as a SlidePane

The slide pane are the one that appears on the side that may be left or right of the screen. You can open existing modal as the slide pane:

import React from 'react'
import { GlobalModal } from 'react-global-modal'

const Example = () => {
  const openModal = async () => {
    GlobalModal.push({
      component: ComponentText,
      props: {
        test: 'Testing',
      },
      hideHeader: true,
      isSlidePane: true,
    })
  }

  return (
    <div>
      <button onClick={openModal}>Open</button>
    </div>
  )
}
const ComponentText = ({ test }: { test: string }) => {
  return (
    <div
      style={{
        height: '400px',
      }}
    >
      <div
        style={{
          height: '2rem',
        }}
      >
        Header
      </div>
      hello {test}
      <div
        style={{
          position: 'absolute',
          left: 0,
          bottom: 0,
          width: '100%',
          borderTop: '1px solid rgb(230 232 240)',
        }}
      >
        <div
          style={{
            display: 'flex',
            flexDirection: 'row',
            padding: '8px 10px',
            justifyContent: 'flex-end',
            gridGap: '5px',
          }}
        >
          <button className="btn btn-error">Close</button>
          <button className="btn btn-primary"> okay</button>
        </div>
      </div>
    </div>
  )
}
export default Example

You can open slide pane by passing the props isSlidePane: true while opening the modal. Their is additional properties for side pane that is position which determines whether you want it be right or left.

Confirmation Modal

Confirmation modal is can be used to ask the user to perform the certain operation. You can invoke the confirmation similarly to that of normal modal.

import React from 'react'
import { ConfirmationModal } from 'react-global-modal'

const Example = () => {
  const openModal = async () => {
    ConfirmationModal({
      onCancel: () => {
        // TODO when user tigger cancel action
      },
      onOkay: () => {
        //TODO when user tigger okay action
      },
      okayLabel: 'Continue',
      cancelLabel: 'Back',
    })
  }

  return (
    <div>
      <button onClick={openModal}>Open</button>
    </div>
  )
}

The confirmation modal can be used like above. It consist of list of properties which are descriped below:

Props Types Required Default Description
confirmationBody React.FC Main component that will be displayed inside modal
title string It is the title of the confirmation modal
message string It is the message that is display inside the body of the modal
onCancel Function It is used to perfrom certain action when the user tigger the cancel action
onOkay Function It is used to perform certain action when the user tigger the okay action
cancelLabel string onCancel action tittle
okayLabel string onOkay action title
isCloseable boolean true It indicate wheather the modal can be closed or not. If true, you can only close the modal manualy from the component inside the modal using the modal close method
className string It is used to provde the styles for outer most element of the modal
confirmationClassName string It is used to provde the styles for inner most content of the modal
actions IButtonProps[] any[]
footer React.ReactNode You can pass custom footer to the modal
okyActionProps Record<any,any> Adjust the styling of the okay or positive action button.
cancelActionProps Record<any,any> Adjust the styling of the cancel or negative action button

Async Confirmation Modal

You can use this modal to perfrom certain action based on the user response.

import React from 'react'
import { AsyncConfirmationModal} from 'react-global-modal'

const Example = () => {
  const openModal = async () => {
    const res = await AsyncConfirmationModal({
      title: 'This is testing',
      message: 'This is message',
    })
    if (res) {
      //TODO if yes agree or press okay
    } else {
      //TODO if user doesn't agree or press cancel
    }
  }

  return (
    <div>
      <button onClick={openModal}>Open</button>
    </div>
  )
}
export default Example

The async confirmation modal can be used like above. It consist of list of properties which are descriped below:

Props Types Required Default Description
confirmationBody React.FC Main component that will be displayed inside modal
title string It is the title of the confirmation modal
message string It is the message that is display inside the body of the modal
cancelLabel string onCancel action tittle
okayLabel string onOkay action title
isCloseable boolean true It indicate wheather the modal can be closed or not. If true, you can only close the modal manualy from the component inside the modal using the modal close method
className string It is used to provde the styles for outer most element of the modal
confirmationClassName string It is used to provde the styles for inner most content of the modal
actions IButtonProps[] any[]
footer React.ReactNode You can pass custom footer to the modal
okyActionProps Record<any,any> Adjust the styling of the okay or positive action button.
cancelActionProps Record<any,any> Adjust the styling of the cancel or negative action button

Full customization with different UI framework

The react-global-modal support customization of the existing modal which means you can use this package with any UI framework that you are currently working within your project. For customization, you can pass customModal to the GlobalModalWrapper component. At first create the custom modal like bellow:

//This is the example with chackra-ui
import {
  Button,
  Drawer,
  DrawerBody,
  DrawerCloseButton,
  DrawerContent,
  DrawerFooter,
  DrawerHeader,
  DrawerOverlay,
  Modal,
  ModalBody,
  ModalCloseButton,
  ModalContent,
  ModalFooter,
  ModalHeader,
  ModalOverlay,
} from '@chakra-ui/react'
import React from 'react'
import { IModalProps } from 'react-global-modal'
type IAntModalProps = IModalProps & {
  width?: number
  scrollBehavior?: 'inside' | 'outside'
  isCentered?: boolean
  size: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'full'
}
export const CustomModalComponent = React.forwardRef((propsValues: IAntModalProps, ref) => {
  const {
    children,
    open = false,
    isCloseable,
    title = 'Modal Header',
    onModalClose = () => {},
    footer,
    closeIconComponent,
    actions = [],
    isSlidePane = false,
    position,
    hideHeader,
    scrollBehavior = 'inside',
    isCentered = false,
    size = 'md',
  } = propsValues

  if (isSlidePane) {
    return (
      <Drawer placement={position} isOpen={open} onClose={onModalClose} size={size}>
        <DrawerOverlay />
        <DrawerContent>
          {!isCloseable && (!closeIconComponent ? <DrawerCloseButton /> : closeIconComponent)}
          {!hideHeader && <DrawerHeader>{title}</DrawerHeader>}
          <DrawerBody padding={0} position="relative">
            {children}
          </DrawerBody>
          {footer && footer}
          {actions.length > 0 && !footer && (
            <DrawerFooter>
              {actions.map((el: any) => (
                <Button
                  key={el.title}
                  colorScheme={el.colorScheme}
                  mr={3}
                  onClick={el.onClick}
                  variant={el.variant ?? 'ghost'}
                >
                  {el.title}
                </Button>
              ))}
            </DrawerFooter>
          )}
        </DrawerContent>
      </Drawer>
    )
  }
  return (
    <Modal
      isOpen={open}
      onClose={onModalClose}
      closeOnOverlayClick={!isCloseable}
      scrollBehavior={scrollBehavior}
      isCentered={isCentered}
      size={size}
    >
      <ModalOverlay />
      <ModalContent>
        {!hideHeader && <ModalHeader>Modal Title</ModalHeader>}
        {!isCloseable && <ModalCloseButton />}
        <ModalBody padding={0} position="relative">
          {children}
        </ModalBody>
        {footer && footer}
        {actions.length > 0 && !footer && (
          <ModalFooter>
            {actions.map((el: any) => (
              <Button
                key={el.title}
                colorScheme={el.colorScheme}
                mr={3}
                onClick={el.onClick}
                variant={el.variant ?? 'ghost'}
              >
                {el.title}
              </Button>
            ))}
          </ModalFooter>
        )}
      </ModalContent>
    </Modal>
  )
})

After creating the custom modal, pass the custom modal to GlobalModalWrapper component.

 <GlobalModalWrapper customModal={CustomModalComponent} ref={(el) => (globalModalRef = el)} />

Below are the some example with different UI framework using which you can replace the existing modal with your own custom modal

1. With TailwindCSS

For working with react-global-modal and tailwindCss, you can check the Example

2. With chakra-ui

For working with react-global-modal and chakra ui, you can check the Example

3. With antd

For working with react-global-modal and ant design, you can check the Example

4. With material-ui

For working with react-global-modal and material ui, you can check the Example

5. simple example with package itself

For working with react-global-modal, you can check the Example

Note: In the case of customization, if you need more props you can pass the prop while opening the modal and can access the same prop in your custom modal. You can also observe this in the example.

License

MIT ยฉ bigyanpoudel

react-global-modal's People

Contributors

bigyanpoudel avatar dependabot[bot] avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar

Watchers

 avatar

Forkers

scgdigital

react-global-modal's Issues

Error during building application with Vite

Hi there!
I am facing an issue during the building application with Vite. I migrating from create-react-app to Vite and applications works fine during the development. But I am facing an issue while building.

vite v4.3.8 building for production...
โœ“ 2132 modules transformed.
โœ“ built in 3.60s
"Modal" is not exported by "node_modules/react-modal-global/dist/index.ts", imported by "src/app/areas/asset/Asset.tsx".
file: /Users/maxmudov/enigma/liquid-web-frontend-platform/src/app/areas/asset/Asset.tsx:3:9
1: import { ReactNode, useEffect, useMemo } from 'react'
2: import { useTranslation } from 'react-i18next'
3: import { Modal } from 'react-modal-global'
            ^
4: import { Link } from 'react-router-dom'
5: import ReactGA from 'react-ga4'
error during build:
RollupError: "Modal" is not exported by "node_modules/react-modal-global/dist/index.ts", imported by "src/app/areas/asset/Asset.tsx".
    at error (file:///Users/maxmudov/enigma/liquid-web-frontend-platform/node_modules/rollup/dist/es/shared/node-entry.js:2124:30)
...

How to place GlobalModalWrapper inside RouterProvider

Hi,

Context

I'm integrating global modal in an existing application whose app.tsx looks like this:

export constApp: React.FC<AppProps> = ({
  appId,
  application,
}) => {
  const resolvedApp = application ?? ApplicationLoader.load(appId);
  const app = Parser.parseApplication(resolvedApp);

  const globalModalRef = useRef(null);
  useEffect(() => {
    GlobalModal.setUpModal(globalModalRef.current);
  }, []);

  const router = useMemo(
    () =>
      createBrowserRouter([
        {
          path: "/",
          element: <Entry entry={app.home} />,
          errorElement: <ErrorPage />,
          children: app.screens.map((screen) => {
            return {
              path: `${screen.name.toLowerCase()}`,
              element: <Screen key={screenId} screen={screen} />,
            };
          }),
        },
      ]),
    [app],
  );
  return (
    <ApplicationContextProvider app={app}>
      <ThemeProvider>
        <RouterProvider router={router} />
        <ToastContainer />
        <GlobalModalWrapper
          customModal={CustomModalComponent}
          ref={globalModalRef}
        />
      </ThemeProvider>
    </ApplicationContextProvider>
  );
};

Issue

I have some components which I wanna show in Modal that use useNavigate and other hooks.
So, when i do something like this:

GlobalModal.push({
      component: () => <Screen screen={screen} />,
    });

It throws this error:
Screenshot 2023-10-11 at 6 30 40 PM

Potential Cause

I think its wrong placement/way the GlobalModalWrapper is configured in my app, can you point out the issue here please?

How to close/pop opened Modal before opening next one

Context

I'm opening up new Modal from inside a Modal,
I want behavior such that when new Modal is opened, it checks wether any other Modal is already opened? if it is, close it first and then open up a new Modal

Ideal Solution

To open up a new Modal when it's the first time of the application lifecycle,
And, just update the content/props of the existing modal rather than closing or opening.

Tried Methods

Tried these methods before calling GlobalModal.push

  • GlobalModal.pop(0) / GlobalModal.pop()
    it creates a modal and removes it almost instantaneously (i.e., a Modal is never displayed) (noticed this behavior through inspect tab -> elements)

  • GlobalModal.closeAll()
    it doesn't do anything when first Modal is opened, but when second Modal is opened (from within first one), it closes both modals, and upper behavior (as described for GlobalModal.pop()) repeats when tried to open the first modal again

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.