Skip to content

Commit

Permalink
feat(modal): Add option to disable overlay click (#158)
Browse files Browse the repository at this point in the history
* feat(modal): Add option to disable overlay click

- Updated types

* chore(modal): Renamed export
  • Loading branch information
hachiojidev authored Feb 2, 2021
1 parent a331366 commit fbe334a
Show file tree
Hide file tree
Showing 6 changed files with 46 additions and 14 deletions.
4 changes: 2 additions & 2 deletions src/widgets/Modal/Modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ import Heading from "../../components/Heading/Heading";
import Button from "../../components/Button/Button";
import Flex from "../../components/Flex/Flex";
import { CloseIcon } from "../../components/Svg";
import { ModalProps } from "./types";
import { InjectedProps } from "./types";

interface Props extends ModalProps {
interface Props extends InjectedProps {
title: string;
}

Expand Down
17 changes: 14 additions & 3 deletions src/widgets/Modal/ModalContext.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import React, { createContext, useState } from "react";
import styled from "styled-components";
import Overlay from "../../components/Overlay/Overlay";
import { ModalProps } from "./types";
import { Handler } from "./types";

interface ModalsContext extends ModalProps {
interface ModalsContext {
onPresent: (node: React.ReactNode, key?: string) => void;
onDismiss: Handler;
setCloseOnOverlayClick: React.Dispatch<React.SetStateAction<boolean>>;
}

const ModalWrapper = styled.div`
Expand All @@ -23,11 +25,13 @@ const ModalWrapper = styled.div`
export const Context = createContext<ModalsContext>({
onPresent: () => null,
onDismiss: () => null,
setCloseOnOverlayClick: () => true,
});

const ModalProvider: React.FC = ({ children }) => {
const [isOpen, setIsOpen] = useState(false);
const [modalNode, setModalNode] = useState<React.ReactNode>();
const [closeOnOverlayClick, setCloseOnOverlayClick] = useState(true);

const handlePresent = (node: React.ReactNode) => {
setModalNode(node);
Expand All @@ -39,16 +43,23 @@ const ModalProvider: React.FC = ({ children }) => {
setIsOpen(false);
};

const handleOverlayDismiss = () => {
if (closeOnOverlayClick) {
handleDismiss();
}
};

return (
<Context.Provider
value={{
onPresent: handlePresent,
onDismiss: handleDismiss,
setCloseOnOverlayClick,
}}
>
{isOpen && (
<ModalWrapper>
<Overlay show onClick={handleDismiss} />
<Overlay show onClick={handleOverlayDismiss} />
{React.isValidElement(modalNode) &&
React.cloneElement(modalNode, {
onDismiss: handleDismiss,
Expand Down
20 changes: 17 additions & 3 deletions src/widgets/Modal/index.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from "react";
import noop from "lodash/noop";
import { Modal, useModal } from ".";
import { InjectedProps } from "./types";
import Button from "../../components/Button/Button";
import Heading from "../../components/Heading/Heading";

Expand All @@ -10,8 +10,12 @@ export default {
argTypes: {},
};

const CustomModal = ({ title }) => (
<Modal title={title} onDismiss={noop}>
interface CustomModalProps extends InjectedProps {
title: string;
}

const CustomModal: React.FC<CustomModalProps> = ({ title, onDismiss }) => (
<Modal title={title} onDismiss={onDismiss}>
<Heading>{title}</Heading>
<Button>This button Does nothing</Button>
</Modal>
Expand All @@ -27,3 +31,13 @@ export const Default: React.FC = () => {
</div>
);
};

export const DisableOverlayClick: React.FC = () => {
const [onPresent1] = useModal(<CustomModal title="Modal 1" />, false);

return (
<div>
<Button onClick={onPresent1}>Disabled overlay click</Button>
</div>
);
};
2 changes: 1 addition & 1 deletion src/widgets/Modal/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export { default as Modal } from "./Modal";
export { default as ModalProvider } from "./ModalContext";
export { default as useModal } from "./useModal";
export type { ModalProps } from "./types";
export type { InjectedProps as InjectedModalProps } from "./types";
6 changes: 4 additions & 2 deletions src/widgets/Modal/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ export interface ModalTheme {
background: string;
}

export interface ModalProps {
onDismiss: () => void;
export type Handler = () => void;

export interface InjectedProps {
onDismiss?: Handler;
}
11 changes: 8 additions & 3 deletions src/widgets/Modal/useModal.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
import { useCallback, useContext } from "react";
import { useCallback, useContext, useEffect } from "react";
import { Context } from "./ModalContext";
import { Handler } from "./types";

const useModal = (modal: React.ReactNode): [() => void, () => void] => {
const { onPresent, onDismiss } = useContext(Context);
const useModal = (modal: React.ReactNode, closeOnOverlayClick = true): [Handler, Handler] => {
const { onPresent, onDismiss, setCloseOnOverlayClick } = useContext(Context);
const onPresentCallback = useCallback(() => {
onPresent(modal);
}, [modal, onPresent]);

useEffect(() => {
setCloseOnOverlayClick(closeOnOverlayClick);
}, [closeOnOverlayClick, setCloseOnOverlayClick]);

return [onPresentCallback, onDismiss];
};

Expand Down

0 comments on commit fbe334a

Please sign in to comment.