Skip to content

Commit

Permalink
feat: Add modal (#26)
Browse files Browse the repository at this point in the history
  • Loading branch information
RabbitDoge authored Nov 2, 2020
1 parent ec72553 commit 2a86cda
Show file tree
Hide file tree
Showing 7 changed files with 146 additions and 0 deletions.
17 changes: 17 additions & 0 deletions src/components/Overlay/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import styled from "styled-components";
import { OverlayProps } from "./types";

const Overlay = styled.div.attrs({ role: "presentation" })<OverlayProps>`
position: fixed;
top: 0px;
left: 0px;
width: 100%;
height: 100%;
background-color: #452a7a;
transition: opacity 0.4s;
opacity: ${({ show }) => (show ? 0.6 : 0)};
z-index: 11;
pointer-events: ${({ show }) => (show ? "initial" : "none")};
`;

export default Overlay;
3 changes: 3 additions & 0 deletions src/components/Overlay/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export type OverlayProps = {
show: boolean;
};
12 changes: 12 additions & 0 deletions src/widgets/Modal/Modal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import styled from "styled-components";

const Modal = styled.div`
background: #ffffff;
box-shadow: 0px 20px 36px -8px rgba(14, 14, 44, 0.1), 0px 1px 1px rgba(0, 0, 0, 0.05);
border: 1px solid rgba(14, 14, 44, 0.05);
border-radius: 32px;
padding: 40px;
z-index: 11;
`;

export default Modal;
62 changes: 62 additions & 0 deletions src/widgets/Modal/ModalContext.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import React, { createContext, useState } from "react";
import styled from "styled-components";
import Overlay from "../../components/Overlay";

const ModalWrapper = styled.div`
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
`;

interface ModalsContext {
onPresent: (node: React.ReactNode, key?: string) => void;
onDismiss: () => void;
}

export const Context = createContext<ModalsContext>({
onPresent: () => null,
onDismiss: () => null,
});

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

const handlePresent = (node: React.ReactNode) => {
setModalNode(node);
setIsOpen(true);
};

const handleDismiss = () => {
setModalNode(undefined);
setIsOpen(false);
};

return (
<Context.Provider
value={{
onPresent: handlePresent,
onDismiss: handleDismiss,
}}
>
{isOpen && (
<ModalWrapper>
<Overlay show onClick={handleDismiss} />
{React.isValidElement(modalNode) &&
React.cloneElement(modalNode, {
onDismiss: handleDismiss,
})}
</ModalWrapper>
)}
{children}
</Context.Provider>
);
};

export default Modals;
36 changes: 36 additions & 0 deletions src/widgets/Modal/index.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import React from "react";
import { ModalProvider, Modal, useModal } from ".";
import Button from "../../components/Button";
import Heading from "../../components/Heading";

export default {
title: "Modal",
component: Modal,
argTypes: {},
};

const CustomModal = ({ title }) => (
<Modal>
<Heading>{title}</Heading>
<Button>This button Does nothing</Button>
</Modal>
);

const ModalConsumer = () => {
const [onPresent1] = useModal(<CustomModal title="Modal 1" />);
const [onPresent2] = useModal(<CustomModal title="Modal 2" />);
return (
<div>
<Button onClick={onPresent1}>Open modal 1</Button>
<Button onClick={onPresent2}>Open modal 2</Button>
</div>
);
};

export const Default: React.FC = () => {
return (
<ModalProvider>
<ModalConsumer />
</ModalProvider>
);
};
3 changes: 3 additions & 0 deletions src/widgets/Modal/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export { default as Modal } from "./Modal";
export { default as ModalProvider } from "./ModalContext";
export { default as useModal } from "./useModal";
13 changes: 13 additions & 0 deletions src/widgets/Modal/useModal.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { useCallback, useContext } from "react";
import { Context } from "./ModalContext";

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

return [onPresentCallback, onDismiss];
};

export default useModal;

0 comments on commit 2a86cda

Please sign in to comment.