npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@dinneb/react-use-modal

v1.0.3

Published

A custom hook that provides a flexible and reusable way to manage multiple modals in React applications.

Downloads

7

Readme

useModal

banner2

npm npm bundle size GitHub last commit

react-use-modal is a custom hook that provides a flexible and reusable way to manage modals in React applications.

Use a single line of jsx tag to insert your Modal component in page and use useModal configuration as props. Then go from there: update the same modal with dynamic content with functions provided by the hook.

In its basic implementation useModal lets you manage multiple modals in page in a reusable way without the need to write complex jsx code with as many Modal components (and relative states) as the number of different modals you want.

Highlights

  • Great flexibiliy: use a single jsx tag updated dynamically for all the modals in you page...
  • ...or decouple part of the logic from the hook and manage it yourself in your page/component
  • Small and minified bundle size
  • Type safe with TypeScript

Table of Contents


Installation

To install the package, you can use npm or yarn:

npm install @dinneb/react-use-modal --save

or

yarn add @dinneb/react-use-modal

Usage

Basic

  1. Import the useModal hook
import { useModal } from "@dinneb/react-use-modal";
  1. Call the hook to get modal configuration and relative helper functions: modalConfig and setModalConfig.
const { setModalConfig, modalConfig } = useModal();
  1. Spread modalConfig on your Modal component (you can find an example of a custom Modal component implementation below)
const MyPageComponent = () => {
  const { setModalConfig, modalConfig } = useModal();

  return (
    <>
      ...Some page content here...
      <Modal {...modalConfig} />
    </>
  );
};
  1. Use the setModalConfig function wherever you want passing a configuration object to it.
const MyPageComponent = () => {
  const { setModalConfig, modalConfig } = useModal();

  const handleOpenModal = () => {
    setModalConfig({
      open: true,
      title: "I'm the first modal",
      children:
        "Content message of the modal inside a component of your choice",
      buttons: [
        {
          text: "Confirm",
        },
      ],
    });
  };

  return (
    <>
      ...Some page content here...
      <div onClick={handleOpenModal} className="btn">
        Show modal
      </div>
      <Modal {...modalConfig} />
    </>
  );
};

example1

Basic example: click on "Show modal" button will execute setModalConfig with the config we defined.

Alternative

Update current config partially

Maybe you want to update only part of current modalConfig, let's say we have an open modal and we would like to change part of it's content when the user presses one of it's buttons. We can achieve this by using the functino updateModalConfig returned by the hook like so

const MyPageComponent = () => {
  const { setModalConfig, modalConfig, updateModalConfig } = useModal();

  const handleOpenModal = () => {
    setModalConfig({
      open: true,
      title: "I'm the first modal",
      children:
        "Content message of the modal inside a component of your choice",
      buttons: [
        {
          text: "Cancel",
        },
        {
          text: "Confirm",
          disableClose: true,
          onClick: showSecondModal,
        },
      ],
    });

  const showSecondModal = () => {
    updateModalConfig({
      title: "I'm the second modal",
      children:
        "Are you sure you want to proceed?",
      buttons: [
        {
          text: "Yes, I am!",
        },
      ],
    });
  }


 // ... same jsx content as seen above

};

Here we've added a second button, the cancel button simply abort the operation closing the modal (so has no need for additional handlers, the confirm button is stopped from closing the modal, we pass it a handler which calls updteModalConfig from the hook and we update with it only the parts of the config that we need.

example2

Alternative usage: here you can see updateModalConfig in action, passing from previous config (left) to partially modified one (right).

Decoupled logic

If you have some complex, maybe verbose piece of jsx (eg. for children or buttons) you can decouple some props handling from the hook thus leveraging from it only part of the configuration while managing the other part manually in your page/component, let's see an example for state dependent children.

const initialModalConfig = {
  title: "I'm a complex modal!",
};

const MyPageComponent = () => {
  const { modalConfig, showModal } = useModal(initialModalConfig);
  const [isSomethingActive, setIsSomethingActive] = useState < boolean > false;

  const currentButtons: IModalButton[] = isSomethingActive
    ? [{ text: "Button for active state" }]
    : [{ text: "Inactive btn 1" }, { text: "Inactive btn 2" }];

  return (
    <>
      <div onClick={showModal} className="btn">
        Show modal
      </div>

      <div
        onClick={() => setIsSomethingActive((prev) => !prev)}
        className="btn"
      >
        Toggle active state
      </div>

      <Modal {...modalConfig} buttons={currentButtons}>
        {isSomethingActive ? (
          <div>Some jsx here for the active state</div>
        ) : (
          <div>Some other jsx for inactive state</div>
        )}
      </Modal>
    </>
  );
};

Here yoy can see an example of useModal usage with non-empty initial configuration, showing the modal through showModal function and more importantly the decoupled/rewritten props children and buttons. This pattern can be used for complex, verbose or state dependent content.

example3

Alternative usage: config through hook inital config, modal shown with showModal, rewritten buttons and children Modal props.


Modal Component (coming soon)

At the moment we don't provide the Modal component. The hook provides config and functions, you are supposed to adjust your Modal component to them. Soon we will provide an official Modal too. In the meantime you can find below an example of how we implemented the Modal for the examples seen in this doc.

// Modal.tsx

import { ModalProps } from "@dinneb/react-use-modal";
import styles from "./Modal.module.css";

export const Modal = ({
  open,
  title,
  children,
  handleClose,
  showCloseIcon,
  buttons,
}: ModalProps) => {
  return open ? (
    <>
      <div className={styles.modalBody}>
        {showCloseIcon && (
          <div className={styles.close} onClick={handleClose}></div>
        )}
        <div className={styles.title}>{title}</div>
        <div className={styles.message}>{children}</div>

        <ModalActions handleClose={handleClose} buttons={buttons} />
      </div>
      <div className={styles.overlay} onClick={handleClose}></div>
    </>
  ) : null;
};
// ModalActions.tsx

import { ModalProps } from "@dinneb/react-use-modal";
import styles from "./Modal.module.css";

export const ModalActions = ({
  buttons,
  handleClose,
}: Pick<ModalProps, "buttons" | "handleClose">) => (
  <div className={styles.actions}>
    {buttons?.map(({ text, disableClose, disabled, onClick, style }, idx) => {
      const handleClick = () => {
        !disabled && onClick?.();
        if (!disableClose) handleClose();
      };
      return (
        <div
          key={idx}
          onClick={handleClick}
          className={styles.btn}
          style={style}
        >
          {text}
        </div>
      );
    })}
  </div>
);
/* Modal.module.css */

.overlay {
  position: absolute;
  z-index: 1;
  width: 100%;
  height: 100vh;
  left: 0;
  top: 0;
  background-color: rgba(0, 0, 0, 0.6);
}

.modalBody {
  position: absolute;
  min-width: 300px;
  max-width: 500px;
  min-height: 100px;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  background-color: white;
  border-radius: 10px;
  z-index: 2;
  box-shadow: 0px 5px 20px rgba(0, 0, 0, 0.5);
  padding: 15px;
}

.title {
  font-weight: bold;
  margin-top: 20px;
  font-size: 22px;
}

.message {
  margin: 20px;
  font-size: 16px;
}

.close:after {
  position: absolute;
  right: 20px;
  top: 10px;
  line-height: 1em;
  font-size: 40px;
  display: block;
  content: "\00d7";
  cursor: pointer;
}

.actions {
  display: flex;
  justify-content: center;
  gap: 10px;
  margin-top: 30px;
  margin-bottom: 10px;
}

.btn {
  padding: 8px;
  border-radius: 6px;
  border: 1px solid grey;
  text-align: center;
  min-width: 80px;
  cursor: pointer;
}

API

Properties and methods

IUseModalReturn

| Property | Type | Default | Description | | ------------------- | ----------------------------------------- | ------------------------------------------------------------------------------------------------------------------- | ----------- | | modalConfig | IExtendedModalConfig | The current configuration of the modal (usable to as Modal props), auto inject handleClose function | | setModalConfig | Dispatch<SetStateAction<IModalConfig>> | Replace the entire configuration of the modal with the IModalConfig object provided as the argument | | updateModalConfig | (config: Partial<IModalConfig>) => void | Updates the configuration of the modal with the properties provided in the config object (merge with current state) | | toggleModal | () => void | Toggles the visibility of the modal | | showModal | () => void | Shows the modal | | hideModal | () => void | Hides the modal |

Hook configuration / Modal props

IModalConfig / IExtendedModalConfig

The following properties can be passed as configuration options when calling the useModal hook, or as props to your modal component. Your modal is supposed to have (or extend) the same shape of hook configuration interface: in particular the hook implement IModalConfig interface while the modal is supposed to extend the already extended IExtendedModalConfig the automatically injects also and handleClose function to close the modal when clicking on backdrop or non-disabled buttons.

| Property | Type | Default | Description | | ---------------- | ---------------- | ----------- | --------------------------------------- | | open | boolean | false | Whether the modal is currently open | | title? | string | undefined | The title of the modal | | showCloseIcon? | boolean | undefined | Whether to show top right close icon | | children? | ReactNode | undefined | The content to display within the modal | | buttons? | IModalButton[] | undefined | Whether the modal is currently open |

Buttons

IModalButton

| Property | Type | Default | Description | | --------------- | --------------- | ----------- | --------------------------------------------------------------- | | text | string | `` | The text to display on the button | | style? | CSSProperties | {} | Custom styles to apply to the button | | onClick? | () => void | undefined | A function to execute when the button is clicked | | disabled? | boolean | undefined | Whether the button should be disabled | | disableClose? | boolean | undefined | Whether the modal should be kept open after clicking the button |


Technologies

This is project is built with 💙 on top of:

  • React.js: The library for web and native user interfaces

  • Rollup: The JavaScript module bundler

  • Terser: JavaScript mangler and compressor toolkit for ES6+

  • Babel: A JavaScript compiler

  • Typescript: A strongly typed programming language that builds on JavaScript

Contributors

Although I am committing the code of this project, life is always a team effort. Here you can find a list of people who contributed to this repo.