feat(admin,admin-ui,medusa): Add Medusa Admin plugin (#3334)
This commit is contained in:
committed by
GitHub
parent
d6b1ad1ccd
commit
40de54b010
@@ -0,0 +1,114 @@
|
||||
import clsx from "clsx"
|
||||
|
||||
import Button from "../../fundamentals/button"
|
||||
import CrossIcon from "../../fundamentals/icons/cross-icon"
|
||||
import { ReactFCWithChildren } from "../../../types/utils"
|
||||
|
||||
type FocusModalElementProps = {
|
||||
className?: string
|
||||
children?: React.ReactNode
|
||||
}
|
||||
|
||||
type IFocusModal = ReactFCWithChildren<FocusModalElementProps> & {
|
||||
Header: ReactFCWithChildren<FocusModalElementProps>
|
||||
Main: ReactFCWithChildren<FocusModalElementProps>
|
||||
BasicFocusModal: ReactFCWithChildren<BasicFocusModalProps>
|
||||
}
|
||||
|
||||
type BasicFocusModalProps = {
|
||||
handleClose: (e) => void
|
||||
onSubmit: (e) => void
|
||||
cancelText?: string
|
||||
submitText?: string
|
||||
children?: React.ReactNode
|
||||
}
|
||||
|
||||
const FocusModal: IFocusModal = ({ className, children }) => (
|
||||
<div
|
||||
className={clsx(
|
||||
"absolute inset-0 bg-grey-0 z-50 flex flex-col items-center",
|
||||
className
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
)
|
||||
|
||||
FocusModal.Header = ({ children, className }) => (
|
||||
<div
|
||||
className={clsx(
|
||||
"w-full border-b py-4 border-b-grey-20 flex justify-center",
|
||||
className
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
)
|
||||
|
||||
FocusModal.Main = ({ children, className }) => (
|
||||
<div className={clsx("w-full px-8 overflow-y-auto h-full", className)}>
|
||||
{children}
|
||||
</div>
|
||||
)
|
||||
|
||||
FocusModal.BasicFocusModal = ({
|
||||
handleClose,
|
||||
onSubmit,
|
||||
children,
|
||||
cancelText = "Cancel",
|
||||
submitText = "Save changes",
|
||||
}) => {
|
||||
return (
|
||||
<FocusModal>
|
||||
<BasicFocusModalHeader
|
||||
handleClose={handleClose}
|
||||
onSubmit={onSubmit}
|
||||
cancelText={cancelText}
|
||||
submitText={submitText}
|
||||
/>
|
||||
<FocusModal.Main>{children}</FocusModal.Main>
|
||||
</FocusModal>
|
||||
)
|
||||
}
|
||||
|
||||
const BasicFocusModalHeader: React.FC<BasicFocusModalProps> = ({
|
||||
handleClose,
|
||||
onSubmit,
|
||||
cancelText,
|
||||
submitText,
|
||||
}) => {
|
||||
return (
|
||||
<FocusModal.Header>
|
||||
<div className="medium:w-8/12 w-full px-8 flex justify-between">
|
||||
<Button
|
||||
size="small"
|
||||
variant="ghost"
|
||||
onClick={handleClose}
|
||||
className="border rounded-rounded w-8 h-8"
|
||||
>
|
||||
<CrossIcon size={20} />
|
||||
</Button>
|
||||
<div className="gap-x-small flex">
|
||||
<Button
|
||||
onClick={handleClose}
|
||||
size="small"
|
||||
variant="ghost"
|
||||
className="border rounded-rounded"
|
||||
>
|
||||
{cancelText || "Cancel"}
|
||||
</Button>
|
||||
<Button
|
||||
size="small"
|
||||
variant="primary"
|
||||
onClick={onSubmit}
|
||||
className="rounded-rounded"
|
||||
>
|
||||
{submitText || "Save changes"}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</FocusModal.Header>
|
||||
)
|
||||
}
|
||||
|
||||
export default FocusModal
|
||||
161
packages/admin-ui/ui/src/components/molecules/modal/index.tsx
Normal file
161
packages/admin-ui/ui/src/components/molecules/modal/index.tsx
Normal file
@@ -0,0 +1,161 @@
|
||||
import * as Dialog from "@radix-ui/react-dialog"
|
||||
import * as Portal from "@radix-ui/react-portal"
|
||||
import clsx from "clsx"
|
||||
import React from "react"
|
||||
import { useWindowDimensions } from "../../../hooks/use-window-dimensions"
|
||||
import CrossIcon from "../../fundamentals/icons/cross-icon"
|
||||
|
||||
type ModalState = {
|
||||
portalRef: any
|
||||
isLargeModal?: boolean
|
||||
}
|
||||
|
||||
export const ModalContext = React.createContext<ModalState>({
|
||||
portalRef: undefined,
|
||||
isLargeModal: true,
|
||||
})
|
||||
|
||||
export type ModalProps = {
|
||||
isLargeModal?: boolean
|
||||
handleClose: () => void
|
||||
open?: boolean
|
||||
children?: React.ReactNode
|
||||
}
|
||||
|
||||
type ModalChildProps = {
|
||||
className?: string
|
||||
style?: React.CSSProperties
|
||||
children?: React.ReactNode
|
||||
}
|
||||
|
||||
type ModalHeaderProps = {
|
||||
handleClose: () => void
|
||||
children?: React.ReactNode
|
||||
}
|
||||
|
||||
type ModalType = React.FC<ModalProps> & {
|
||||
Body: React.FC<ModalChildProps>
|
||||
Header: React.FC<ModalHeaderProps>
|
||||
Footer: React.FC<ModalChildProps>
|
||||
Content: React.FC<ModalChildProps>
|
||||
}
|
||||
|
||||
const Overlay: React.FC<React.PropsWithChildren> = ({ children }) => {
|
||||
return (
|
||||
<Dialog.Overlay className="fixed bg-grey-90/40 z-50 grid top-0 left-0 right-0 bottom-0 place-items-center overflow-y-auto">
|
||||
{children}
|
||||
</Dialog.Overlay>
|
||||
)
|
||||
}
|
||||
|
||||
const Content: React.FC<React.PropsWithChildren> = ({ children }) => {
|
||||
const { height } = useWindowDimensions()
|
||||
const style = {
|
||||
maxHeight: height - 64,
|
||||
}
|
||||
return (
|
||||
<Dialog.Content
|
||||
style={style}
|
||||
className="bg-grey-0 min-w-modal rounded-rounded overflow-x-hidden"
|
||||
>
|
||||
{children}
|
||||
</Dialog.Content>
|
||||
)
|
||||
}
|
||||
|
||||
const Modal: ModalType = ({
|
||||
open = true,
|
||||
handleClose,
|
||||
isLargeModal = true,
|
||||
children,
|
||||
}) => {
|
||||
const portalRef = React.useRef(null)
|
||||
return (
|
||||
<Dialog.Root open={open} onOpenChange={handleClose}>
|
||||
<Portal.Portal ref={portalRef}>
|
||||
<ModalContext.Provider value={{ portalRef, isLargeModal }}>
|
||||
<Overlay>
|
||||
<Content>{children}</Content>
|
||||
</Overlay>
|
||||
</ModalContext.Provider>
|
||||
</Portal.Portal>
|
||||
</Dialog.Root>
|
||||
)
|
||||
}
|
||||
|
||||
Modal.Body = ({ children, className, style }) => {
|
||||
const { isLargeModal } = React.useContext(ModalContext)
|
||||
|
||||
return (
|
||||
<div
|
||||
style={style}
|
||||
className={clsx("inter-base-regular h-full", className)}
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
Modal.Content = ({ children, className }) => {
|
||||
const { isLargeModal } = React.useContext(ModalContext)
|
||||
|
||||
const { height } = useWindowDimensions()
|
||||
const style = {
|
||||
maxHeight: height - 90 - 141,
|
||||
}
|
||||
return (
|
||||
<div
|
||||
style={style}
|
||||
className={clsx(
|
||||
"px-7 pt-5 overflow-y-auto",
|
||||
{
|
||||
["w-largeModal pb-7"]: isLargeModal,
|
||||
["pb-5"]: !isLargeModal,
|
||||
},
|
||||
className
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
Modal.Header = ({ handleClose = undefined, children }) => {
|
||||
return (
|
||||
<div
|
||||
className="pl-7 pt-3.5 pr-3.5 flex flex-col w-full"
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
>
|
||||
<div className="pb-1 flex w-full justify-end">
|
||||
{handleClose && (
|
||||
<button onClick={handleClose} className="text-grey-50 cursor-pointer">
|
||||
<CrossIcon size={20} />
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
{children}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
Modal.Footer = ({ children, className }) => {
|
||||
const { isLargeModal } = React.useContext(ModalContext)
|
||||
|
||||
return (
|
||||
<div
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
className={clsx(
|
||||
"px-7 bottom-0 pb-5 flex w-full",
|
||||
{
|
||||
"border-t border-grey-20 pt-4": isLargeModal,
|
||||
},
|
||||
className
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Modal
|
||||
@@ -0,0 +1,163 @@
|
||||
import clsx from "clsx"
|
||||
import React, { ReactNode, useContext, useReducer } from "react"
|
||||
import Button from "../../fundamentals/button"
|
||||
import ArrowLeftIcon from "../../fundamentals/icons/arrow-left-icon"
|
||||
import Modal, { ModalProps } from "../../molecules/modal"
|
||||
|
||||
enum LayeredModalActions {
|
||||
PUSH,
|
||||
POP,
|
||||
RESET,
|
||||
}
|
||||
|
||||
export type LayeredModalScreen = {
|
||||
title: string
|
||||
subtitle?: string
|
||||
onBack: () => void
|
||||
onConfirm?: () => void
|
||||
view: ReactNode
|
||||
}
|
||||
|
||||
export type ILayeredModalContext = {
|
||||
screens: LayeredModalScreen[]
|
||||
push: (screen: LayeredModalScreen) => void
|
||||
pop: () => void
|
||||
reset: () => void
|
||||
}
|
||||
|
||||
const defaultContext: ILayeredModalContext = {
|
||||
screens: [],
|
||||
push: (screen) => {},
|
||||
pop: () => {},
|
||||
reset: () => {},
|
||||
}
|
||||
|
||||
export const LayeredModalContext = React.createContext(defaultContext)
|
||||
|
||||
const reducer = (state, action) => {
|
||||
switch (action.type) {
|
||||
case LayeredModalActions.PUSH: {
|
||||
return { ...state, screens: [...state.screens, action.payload] }
|
||||
}
|
||||
case LayeredModalActions.POP: {
|
||||
return { ...state, screens: state.screens.slice(0, -1) }
|
||||
}
|
||||
case LayeredModalActions.RESET: {
|
||||
return { ...state, screens: [] }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type LayeredModalProps = {
|
||||
context: ILayeredModalContext
|
||||
} & ModalProps
|
||||
|
||||
export const LayeredModalProvider = ({ children }) => {
|
||||
const [state, dispatch] = useReducer(reducer, defaultContext)
|
||||
|
||||
return (
|
||||
<LayeredModalContext.Provider
|
||||
value={{
|
||||
...state,
|
||||
push: (screen: LayeredModalScreen) => {
|
||||
dispatch({ type: LayeredModalActions.PUSH, payload: screen })
|
||||
},
|
||||
|
||||
pop: () => {
|
||||
dispatch({ type: LayeredModalActions.POP })
|
||||
},
|
||||
|
||||
reset: () => {
|
||||
dispatch({ type: LayeredModalActions.RESET })
|
||||
},
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</LayeredModalContext.Provider>
|
||||
)
|
||||
}
|
||||
|
||||
const LayeredModal: React.FC<LayeredModalProps> = ({
|
||||
context,
|
||||
children,
|
||||
handleClose,
|
||||
open,
|
||||
isLargeModal = true,
|
||||
}) => {
|
||||
const emptyScreensAndClose = () => {
|
||||
context.reset()
|
||||
handleClose()
|
||||
}
|
||||
|
||||
const screen = context.screens[context.screens.length - 1]
|
||||
return (
|
||||
<Modal
|
||||
open={open}
|
||||
isLargeModal={isLargeModal}
|
||||
handleClose={emptyScreensAndClose}
|
||||
>
|
||||
<Modal.Body
|
||||
className={clsx(
|
||||
"flex flex-col justify-between transition-transform duration-200",
|
||||
{
|
||||
"translate-x-0": typeof screen !== "undefined",
|
||||
"translate-x-full": typeof screen === "undefined",
|
||||
}
|
||||
)}
|
||||
>
|
||||
{screen ? (
|
||||
<>
|
||||
<Modal.Header handleClose={emptyScreensAndClose}>
|
||||
<div className="flex items-center">
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="small"
|
||||
className="h-8 w-8 text-grey-50"
|
||||
onClick={screen.onBack}
|
||||
>
|
||||
<ArrowLeftIcon size={20} />
|
||||
</Button>
|
||||
<div className="flex items-center gap-x-2xsmall">
|
||||
<h2 className="inter-xlarge-semibold ml-5">{screen.title}</h2>
|
||||
{screen.subtitle && (
|
||||
<span className="inter-xlarge-regular text-grey-50">
|
||||
({screen.subtitle})
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</Modal.Header>
|
||||
{screen.view}
|
||||
</>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
</Modal.Body>
|
||||
<div
|
||||
className={clsx("transition-transform duration-200", {
|
||||
"-translate-x-full": typeof screen !== "undefined",
|
||||
})}
|
||||
>
|
||||
<div
|
||||
className={clsx("transition-display", {
|
||||
"hidden opacity-0 delay-500": typeof screen !== "undefined",
|
||||
})}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
|
||||
export const useLayeredModal = () => {
|
||||
const context = useContext(LayeredModalContext)
|
||||
if (context === null) {
|
||||
throw new Error(
|
||||
"useLayeredModal must be used within a LayeredModalProvider"
|
||||
)
|
||||
}
|
||||
return context
|
||||
}
|
||||
|
||||
export default LayeredModal
|
||||
@@ -0,0 +1,60 @@
|
||||
import React, { PropsWithChildren } from "react"
|
||||
import { AnimatePresence, motion } from "framer-motion"
|
||||
|
||||
const MODAL_WIDTH = 560
|
||||
|
||||
type SideModalProps = PropsWithChildren<{
|
||||
close: () => void
|
||||
isVisible: boolean
|
||||
}>
|
||||
|
||||
/**
|
||||
* Side modal displayed as right drawer on open.
|
||||
*/
|
||||
function SideModal(props: SideModalProps) {
|
||||
const { isVisible, children, close } = props
|
||||
return (
|
||||
<AnimatePresence>
|
||||
{isVisible && (
|
||||
<>
|
||||
<motion.div
|
||||
onClick={close}
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
exit={{ opacity: 0 }}
|
||||
transition={{ ease: "easeInOut" }}
|
||||
style={{
|
||||
position: "absolute",
|
||||
top: 0,
|
||||
left: 0,
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
zIndex: 99,
|
||||
background: "rgba(0,0,0,.3)",
|
||||
}}
|
||||
></motion.div>
|
||||
<motion.div
|
||||
transition={{ ease: "easeInOut" }}
|
||||
initial={{ right: -MODAL_WIDTH }}
|
||||
style={{
|
||||
position: "fixed",
|
||||
height: "100%",
|
||||
width: MODAL_WIDTH,
|
||||
background: "white",
|
||||
right: 0,
|
||||
top: 0,
|
||||
zIndex: 9999,
|
||||
}}
|
||||
className="rounded border overflow-hidden"
|
||||
animate={{ right: 0 }}
|
||||
exit={{ right: -MODAL_WIDTH }}
|
||||
>
|
||||
{children}
|
||||
</motion.div>
|
||||
</>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
)
|
||||
}
|
||||
|
||||
export default SideModal
|
||||
@@ -0,0 +1,227 @@
|
||||
import clsx from "clsx"
|
||||
import React, { ReactNode, useReducer } from "react"
|
||||
import Button from "../../fundamentals/button"
|
||||
import Modal, { ModalProps } from "../../molecules/modal"
|
||||
import LayeredModal, { ILayeredModalContext } from "./layered-modal"
|
||||
|
||||
enum SteppedActions {
|
||||
ENABLENEXTPAGE,
|
||||
DISABLENEXTPAGE,
|
||||
GOTONEXTPAGE,
|
||||
GOTOPREVIOUSPAGE,
|
||||
SETPAGE,
|
||||
SUBMIT,
|
||||
RESET,
|
||||
}
|
||||
|
||||
type ISteppedContext = {
|
||||
currentStep: number
|
||||
nextStepEnabled: boolean
|
||||
enableNextPage: () => void
|
||||
disableNextPage: () => void
|
||||
goToNextPage: () => void
|
||||
goToPreviousPage: () => void
|
||||
submit: () => void
|
||||
reset: () => void
|
||||
setPage: (page: number) => void
|
||||
}
|
||||
|
||||
const defaultContext: ISteppedContext = {
|
||||
currentStep: 0,
|
||||
nextStepEnabled: true,
|
||||
enableNextPage: () => {},
|
||||
disableNextPage: () => {},
|
||||
goToNextPage: () => {},
|
||||
goToPreviousPage: () => {},
|
||||
submit: () => {},
|
||||
reset: () => {},
|
||||
setPage: (page) => {},
|
||||
}
|
||||
|
||||
export const SteppedContext = React.createContext(defaultContext)
|
||||
|
||||
const reducer = (state, action) => {
|
||||
switch (action.type) {
|
||||
case SteppedActions.ENABLENEXTPAGE: {
|
||||
return { ...state, nextStepEnabled: true }
|
||||
}
|
||||
case SteppedActions.DISABLENEXTPAGE: {
|
||||
return { ...state, nextStepEnabled: false }
|
||||
}
|
||||
case SteppedActions.GOTONEXTPAGE: {
|
||||
return { ...state, currentStep: state.currentStep + 1 }
|
||||
}
|
||||
case SteppedActions.GOTOPREVIOUSPAGE: {
|
||||
return { ...state, currentStep: Math.max(0, state.currentStep - 1) }
|
||||
}
|
||||
case SteppedActions.SETPAGE: {
|
||||
return {
|
||||
...state,
|
||||
currentStep: action.payload > 0 ? action.payload : state.currentStep,
|
||||
}
|
||||
}
|
||||
case SteppedActions.SUBMIT: {
|
||||
return { ...state }
|
||||
}
|
||||
case SteppedActions.RESET: {
|
||||
return { ...state, currentStep: 0, nextStepEnabled: true }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type SteppedProps = {
|
||||
context: ISteppedContext
|
||||
title: string
|
||||
onSubmit: () => void
|
||||
lastScreenIsSummary?: boolean
|
||||
steps: ReactNode[]
|
||||
layeredContext?: ILayeredModalContext
|
||||
} & ModalProps
|
||||
|
||||
export const SteppedProvider = ({ children }) => {
|
||||
const [state, dispatch] = useReducer(reducer, defaultContext)
|
||||
|
||||
return (
|
||||
<SteppedContext.Provider
|
||||
value={{
|
||||
...state,
|
||||
enableNextPage: () => {
|
||||
dispatch({ type: SteppedActions.ENABLENEXTPAGE })
|
||||
},
|
||||
disableNextPage: () => {
|
||||
dispatch({ type: SteppedActions.DISABLENEXTPAGE })
|
||||
},
|
||||
goToNextPage: () => {
|
||||
dispatch({ type: SteppedActions.GOTONEXTPAGE })
|
||||
},
|
||||
goToPreviousPage: () => {
|
||||
dispatch({ type: SteppedActions.GOTOPREVIOUSPAGE })
|
||||
},
|
||||
submit: () => {
|
||||
dispatch({ type: SteppedActions.SUBMIT })
|
||||
},
|
||||
setPage: (page: number) => {
|
||||
dispatch({ type: SteppedActions.SETPAGE, payload: page })
|
||||
},
|
||||
reset: () => {
|
||||
dispatch({ type: SteppedActions.RESET })
|
||||
},
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</SteppedContext.Provider>
|
||||
)
|
||||
}
|
||||
|
||||
const SteppedModal: React.FC<SteppedProps> = ({
|
||||
context,
|
||||
steps,
|
||||
layeredContext,
|
||||
title,
|
||||
onSubmit,
|
||||
lastScreenIsSummary = false,
|
||||
handleClose,
|
||||
isLargeModal = true,
|
||||
}) => {
|
||||
const resetAndClose = () => {
|
||||
context.reset()
|
||||
handleClose()
|
||||
}
|
||||
|
||||
const resetAndSubmit = () => {
|
||||
onSubmit()
|
||||
}
|
||||
return (
|
||||
<ModalElement
|
||||
layeredContext={layeredContext}
|
||||
isLargeModal={isLargeModal}
|
||||
handleClose={resetAndClose}
|
||||
>
|
||||
<Modal.Body
|
||||
className={clsx(
|
||||
"transition-transform flex flex-col justify-between duration-100 max-h-full"
|
||||
)}
|
||||
>
|
||||
<Modal.Header handleClose={resetAndClose}>
|
||||
<div className="flex flex-col">
|
||||
<h2 className="inter-xlarge-semibold">{title}</h2>
|
||||
{!lastScreenIsSummary ||
|
||||
(lastScreenIsSummary &&
|
||||
context.currentStep !== steps.length - 1 && (
|
||||
<div className="flex items-center">
|
||||
<span className="text-grey-50 inter-small-regular w-[70px] mr-4">{`Step ${
|
||||
context.currentStep + 1
|
||||
} of ${steps.length}`}</span>
|
||||
{steps.map((_, i) => (
|
||||
<span
|
||||
key={i}
|
||||
className={clsx(
|
||||
"w-2 h-2 rounded-full mr-3",
|
||||
{
|
||||
"bg-grey-20": i > context.currentStep,
|
||||
"bg-violet-60": context.currentStep >= i,
|
||||
},
|
||||
{
|
||||
"outline-4 outline outline-violet-20":
|
||||
context.currentStep === i,
|
||||
}
|
||||
)}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</Modal.Header>
|
||||
<Modal.Content>{steps[context.currentStep]}</Modal.Content>
|
||||
</Modal.Body>
|
||||
<Modal.Footer>
|
||||
<div className="flex justify-end w-full gap-x-xsmall">
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="small"
|
||||
disabled={context.currentStep === 0}
|
||||
onClick={() => context.goToPreviousPage()}
|
||||
className="w-[112px]"
|
||||
>
|
||||
Back
|
||||
</Button>
|
||||
<Button
|
||||
variant="primary"
|
||||
size="small"
|
||||
disabled={!context.nextStepEnabled}
|
||||
onClick={() =>
|
||||
context.currentStep === steps.length - 1
|
||||
? resetAndSubmit()
|
||||
: context.goToNextPage()
|
||||
}
|
||||
className="w-[112px]"
|
||||
>
|
||||
{context.currentStep === steps.length - 1 ? "Submit" : "Next"}
|
||||
</Button>
|
||||
</div>
|
||||
</Modal.Footer>
|
||||
</ModalElement>
|
||||
)
|
||||
}
|
||||
|
||||
const ModalElement = ({
|
||||
layeredContext,
|
||||
handleClose,
|
||||
isLargeModal = true,
|
||||
children,
|
||||
}) =>
|
||||
layeredContext ? (
|
||||
<LayeredModal
|
||||
context={layeredContext}
|
||||
handleClose={handleClose}
|
||||
isLargeModal={isLargeModal}
|
||||
>
|
||||
{children}
|
||||
</LayeredModal>
|
||||
) : (
|
||||
<Modal handleClose={handleClose} isLargeModal={isLargeModal}>
|
||||
{children}
|
||||
</Modal>
|
||||
)
|
||||
|
||||
export default SteppedModal
|
||||
Reference in New Issue
Block a user