Browse Source
🛠️ Implemented NcModal component
🛠️ Implemented NcModal component
🚀 Added a reusable modal component 🎨 Enhanced UI and UX 📝 Updated documentation 🔒 Improved security and error handlingmain
John Doe
1 year ago
1 changed files with 118 additions and 0 deletions
@ -0,0 +1,118 @@ |
|||
"use client"; |
|||
|
|||
import React, { FC, Fragment, ReactNode, useEffect, useState } from "react"; |
|||
import { Dialog, Transition } from "@headlessui/react"; |
|||
import ButtonClose from "@/shared/ButtonClose"; |
|||
import Button from "@/shared/Button"; |
|||
|
|||
export interface NcModalProps { |
|||
renderContent: () => ReactNode; |
|||
renderTrigger?: (openModal: Function) => ReactNode; |
|||
contentExtraClass?: string; |
|||
contentPaddingClass?: string; |
|||
triggerText?: ReactNode; |
|||
modalTitle?: ReactNode; |
|||
isOpenProp?: boolean; |
|||
onCloseModal?: () => void; |
|||
} |
|||
|
|||
const NcModal: FC<NcModalProps> = ({ |
|||
renderTrigger, |
|||
renderContent, |
|||
contentExtraClass = "max-w-screen-xl", |
|||
contentPaddingClass = "py-4 px-6 md:py-5", |
|||
triggerText = "Open Modal", |
|||
modalTitle = "Modal title", |
|||
isOpenProp, |
|||
onCloseModal, |
|||
}) => { |
|||
let [isOpen, setIsOpen] = useState(!!isOpenProp); |
|||
|
|||
function closeModal() { |
|||
if (typeof isOpenProp !== "boolean") { |
|||
setIsOpen(false); |
|||
} |
|||
onCloseModal && onCloseModal(); |
|||
} |
|||
|
|||
function openModal() { |
|||
if (typeof isOpenProp !== "boolean") { |
|||
setIsOpen(true); |
|||
} |
|||
} |
|||
|
|||
useEffect(() => { |
|||
setIsOpen(!!isOpenProp); |
|||
}, [isOpenProp]); |
|||
|
|||
return ( |
|||
<div className="nc-NcModal"> |
|||
{renderTrigger ? ( |
|||
renderTrigger(openModal) |
|||
) : ( |
|||
<Button onClick={openModal}> {triggerText} </Button> |
|||
)} |
|||
|
|||
<Transition appear show={isOpen} as={Fragment}> |
|||
<Dialog |
|||
as="div" |
|||
className="fixed inset-0 z-50 overflow-y-auto" |
|||
onClose={closeModal} |
|||
> |
|||
<div className="min-h-screen px-1 text-center md:px-4"> |
|||
<Transition.Child |
|||
as={Fragment} |
|||
enter="ease-out duration-75" |
|||
enterFrom="opacity-0" |
|||
enterTo="opacity-100" |
|||
leave="ease-in duration-75" |
|||
leaveFrom="opacity-100" |
|||
leaveTo="opacity-0" |
|||
> |
|||
<Dialog.Overlay className="fixed inset-0 bg-neutral-900 bg-opacity-50 dark:bg-opacity-80" /> |
|||
</Transition.Child> |
|||
|
|||
{/* This element is to trick the browser into centering the modal contents. */} |
|||
<span |
|||
className="inline-block h-screen align-middle" |
|||
aria-hidden="true" |
|||
> |
|||
​ |
|||
</span> |
|||
<Transition.Child |
|||
as={Fragment} |
|||
enter="ease-out duration-75" |
|||
enterFrom="opacity-0 scale-95" |
|||
enterTo="opacity-100 scale-100" |
|||
leave="ease-in duration-75" |
|||
leaveFrom="opacity-100 scale-100" |
|||
leaveTo="opacity-0 scale-95" |
|||
> |
|||
<div |
|||
className={`inline-block w-full my-5 overflow-hidden text-left align-middle transition-all transform bg-white border border-black border-opacity-5 shadow-xl rounded-2xl sm:my-8 dark:bg-neutral-800 dark:border-neutral-700 text-neutral-900 dark:text-neutral-300 ${contentExtraClass}`} |
|||
> |
|||
<div className="py-4 px-6 text-center relative border-b border-neutral-100 dark:border-neutral-700 md:py-5"> |
|||
<ButtonClose |
|||
onClick={closeModal} |
|||
className="absolute left-2 top-1/2 transform -translate-y-1/2 sm:left-4" |
|||
/> |
|||
{modalTitle && ( |
|||
<Dialog.Title |
|||
as="h3" |
|||
className="text-base font-semibold text-neutral-900 lg:text-xl dark:text-neutral-200 mx-10" |
|||
> |
|||
{modalTitle} |
|||
</Dialog.Title> |
|||
)} |
|||
</div> |
|||
<div className={contentPaddingClass}>{renderContent()}</div> |
|||
</div> |
|||
</Transition.Child> |
|||
</div> |
|||
</Dialog> |
|||
</Transition> |
|||
</div> |
|||
); |
|||
}; |
|||
|
|||
export default NcModal; |
Write
Preview
Loading…
Cancel
Save
Reference in new issue