-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: added drawer component #2202
Conversation
Signed-off-by: The1111mp <The1111mp@outlook.com>
🦋 Changeset detectedLatest commit: d6cc47f The changes in this PR will be included in the next version bump. This PR includes changesets to release 3 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
@1111mp is attempting to deploy a commit to the NextUI Team on Vercel. A member of the Team first needs to authorize it. |
The latest updates on your projects. Learn more about Vercel for Git ↗︎
|
Signed-off-by: The1111mp <The1111mp@outlook.com>
Hey @1111mp, thank you so much for your contribution! 🚀. I suggest using the Modal component as the base component, given that the Drawer logic and structure are basically the same. We would primarily need to adjust the |
@jrgarciadev I understand what you mean, and it should be so. Or this way, there is no need to develop additional Drawer components, but just add a Drawer example based on the Modal component. I completed the following code locally and it also works well: import {
Modal,
ModalContent,
ModalHeader,
ModalBody,
ModalFooter,
ModalProps,
useDisclosure,
} from "@nextui-org/react";
type DrawerProps = Omit<ModalProps, "placement" | "scrollBehavior"> & {
placement?: "top" | "right" | "bottom" | "left";
scrollBehavior?: "inside" | "outside";
};
const Drawer: React.FC<DrawerProps> = ({
placement = "right",
scrollBehavior = "inside",
size = "md",
motionProps: drawerMotionProps,
...props
}) => {
const {isOpen, onOpen, onOpenChange} = useDisclosure({defaultOpen: false});
const motionProps = React.useMemo(() => {
if (drawerMotionProps !== void 0) return drawerMotionProps;
const key = placement === "left" || placement === "right" ? "x" : "y";
return {
variants: {
enter: {
[key]: 0,
transition: {
[key]: {
bounce: 0,
duration: 0.3,
ease: TRANSITION_EASINGS.ease,
},
},
},
exit: {
[key]: placement === "top" || placement === "left" ? "-100%" : "100%",
transition: {
[key]: {
bounce: 0,
duration: 0.3,
ease: TRANSITION_EASINGS.ease,
},
},
},
},
};
}, [placement, drawerMotionProps]);
const base = useMemo(() => {
const sizeSource = {
xs: "max-h-[20rem]",
sm: "max-h-[24rem]",
md: "max-h-[28rem]",
lg: "max-h-[32rem]",
xl: "max-h-[36rem]",
"2xl": "max-h-[42rem]",
"3xl": "max-h-[48rem]",
"4xl": "max-h-[56rem]",
"5xl": "max-h-[64rem]",
full: "max-h-full",
};
switch (placement) {
case "right": {
return `absolute inset-y-0 right-0 m-0 sm:m-0 max-h-[none] overflow-y-auto rounded-r-none`;
}
case "left": {
return `absolute inset-y-0 left-0 m-0 sm:m-0 max-h-[none] overflow-y-auto rounded-l-none`;
}
case "top": {
return `absolute inset-x-0 top-0 m-0 sm:m-0 max-w-[none] ${sizeSource[size]} overflow-y-auto rounded-t-none`;
}
case "bottom": {
return `absolute inset-x-0 bottom-0 m-0 sm:m-0 max-w-[none] ${sizeSource[size]} overflow-y-auto rounded-b-none`;
}
}
}, [placement, size]);
return (
<>
<Button onPress={onOpen}>Open Modal</Button>
<Modal
isOpen={isOpen}
onOpenChange={onOpenChange}
{...props}
size={size}
scrollBehavior={scrollBehavior}
classNames={{
base: base,
}}
motionProps={motionProps}
>
<ModalContent>
{(onClose) => (
<>
<ModalHeader className="flex flex-col gap-1">Log in</ModalHeader>
<ModalBody>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam pulvinar risus non
risus hendrerit venenatis. Pellentesque sit amet hendrerit risus, sed porttitor
quam.
</p>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam pulvinar risus non
risus hendrerit venenatis. Pellentesque sit amet hendrerit risus, sed porttitor
quam.
</p>
<p>
Magna exercitation reprehenderit magna aute tempor cupidatat consequat elit dolor
adipisicing. Mollit dolor eiusmod sunt ex incididunt cillum quis. Velit duis sit
officia eiusmod Lorem aliqua enim laboris do dolor eiusmod. Et mollit incididunt
nisi consectetur esse laborum eiusmod pariatur proident Lorem eiusmod et. Culpa
deserunt nostrud ad veniam.
</p>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam pulvinar risus non
risus hendrerit venenatis. Pellentesque sit amet hendrerit risus, sed porttitor
quam. Magna exercitation reprehenderit magna aute tempor cupidatat consequat elit
dolor adipisicing. Mollit dolor eiusmod sunt ex incididunt cillum quis. Velit duis
sit officia eiusmod Lorem aliqua enim laboris do dolor eiusmod. Et mollit
incididunt nisi consectetur esse laborum eiusmod pariatur proident Lorem eiusmod
et. Culpa deserunt nostrud ad veniam.
</p>
<p>
Mollit dolor eiusmod sunt ex incididunt cillum quis. Velit duis sit officia
eiusmod Lorem aliqua enim laboris do dolor eiusmod. Et mollit incididunt nisi
consectetur esse laborum eiusmod pariatur proident Lorem eiusmod et. Culpa
deserunt nostrud ad veniam. Lorem ipsum dolor sit amet, consectetur adipiscing
elit. Nullam pulvinar risus non risus hendrerit venenatis. Pellentesque sit amet
hendrerit risus, sed porttitor quam. Magna exercitation reprehenderit magna aute
tempor cupidatat consequat elit dolor adipisicing. Mollit dolor eiusmod sunt ex
incididunt cillum quis. Velit duis sit officia eiusmod Lorem aliqua enim laboris
do dolor eiusmod. Et mollit incididunt nisi consectetur esse laborum eiusmod
pariatur proident Lorem eiusmod et. Culpa deserunt nostrud ad veniam.
</p>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam pulvinar risus non
risus hendrerit venenatis. Pellentesque sit amet hendrerit risus, sed porttitor
quam.
</p>
<p>
Magna exercitation reprehenderit magna aute tempor cupidatat consequat elit dolor
adipisicing. Mollit dolor eiusmod sunt ex incididunt cillum quis. Velit duis sit
officia eiusmod Lorem aliqua enim laboris do dolor eiusmod. Et mollit incididunt
nisi consectetur esse laborum eiusmod pariatur proident Lorem eiusmod et. Culpa
deserunt nostrud ad veniam.
</p>
<p>
Mollit dolor eiusmod sunt ex incididunt cillum quis. Velit duis sit officia
eiusmod Lorem aliqua enim laboris do dolor eiusmod. Et mollit incididunt nisi
consectetur esse laborum eiusmod pariatur proident Lorem eiusmod et. Culpa
deserunt nostrud ad veniam. Lorem ipsum dolor sit amet, consectetur adipiscing
elit. Nullam pulvinar risus non risus hendrerit venenatis. Pellentesque sit amet
hendrerit risus, sed porttitor quam. Magna exercitation reprehenderit magna aute
tempor cupidatat consequat elit dolor adipisicing. Mollit dolor eiusmod sunt ex
incididunt cillum quis. Velit duis sit officia eiusmod Lorem aliqua enim laboris
do dolor eiusmod. Et mollit incididunt nisi consectetur esse laborum eiusmod
pariatur proident Lorem eiusmod et. Culpa deserunt nostrud ad veniam.
</p>
</ModalBody>
<ModalFooter>
<Button color="danger" variant="flat" onPress={onClose}>
Close
</Button>
<Button color="primary" onPress={onClose}>
Sign in
</Button>
</ModalFooter>
</>
)}
</ModalContent>
</Modal>
</>
);
};
// usage in storybook
export const Default = {
render: Drawer,
args: {
// ...defaultProps,
// size: "full",
placement: "top",
scrollBehavior: "outside",
},
}; Just need to do some class style coverage for the Drawer use case. So should the final solution be to add a Drawer usage example to Modal's documentation? |
Nice you could tested it, the final solution should be creating the Drawer component structure by based on the Modal, you'll |
I ended up doing the following:
import {ReactNode, useMemo} from "react";
import {forwardRef} from "@nextui-org/system";
import {UseModalProps} from "./use-modal";
import Modal from "./modal";
import {TRANSITION_EASINGS} from "@nextui-org/framer-transitions";
import {drawer} from "@nextui-org/theme";
import {clsx} from "@nextui-org/shared-utils";
export type DrawerProps = Omit<UseModalProps, "placement" | "scrollBehavior"> & {
/**
* The content of the modal. Usually the ModalContent
*/
children: ReactNode;
placement?: "top" | "right" | "bottom" | "left";
scrollBehavior?: "inside" | "outside";
};
const Drawer = forwardRef<"div", DrawerProps>(
(
{
className,
classNames,
placement = "right",
scrollBehavior = "inside",
size = "md",
motionProps: drawerMotionProps,
children,
...props
},
ref,
) => {
const motionProps = useMemo(() => {
if (drawerMotionProps !== void 0) return drawerMotionProps;
const key = placement === "left" || placement === "right" ? "x" : "y";
return {
variants: {
enter: {
[key]: 0,
transition: {
[key]: {
bounce: 0,
duration: 0.3,
ease: TRANSITION_EASINGS.ease,
},
},
},
exit: {
[key]: placement === "top" || placement === "left" ? "-100%" : "100%",
transition: {
[key]: {
bounce: 0,
duration: 0.3,
ease: TRANSITION_EASINGS.ease,
},
},
},
},
};
}, [placement, drawerMotionProps]);
const baseStyles = clsx(classNames?.base, className);
const slots = useMemo(
() =>
drawer({
size,
placement,
}),
[size, placement],
);
const base = slots.base({class: clsx(baseStyles, {})});
console.log(base);
return (
<Modal
ref={ref}
{...props}
size={size}
scrollBehavior={scrollBehavior}
classNames={{
...classNames,
base: base,
}}
motionProps={motionProps}
>
{children}
</Modal>
);
},
);
Drawer.displayName = "NextUI.Drawer";
export default Drawer;
// ...
import Drawer from "./drawer";
// ...
// add export Drawer
export {Modal, Drawer, ModalContent, ModalHeader, ModalBody, ModalFooter};
// .....
const drawer = tv({
slots: {
base: ["absolute", "m-0", "sm:m-0", "overflow-y-auto"],
},
variants: {
size: {
xs: {
base: "max-w-xs max-h-[20rem]",
},
sm: {
base: "max-w-sm max-h-[24rem]",
},
md: {
base: "max-w-md max-h-[28rem]",
},
lg: {
base: "max-w-lg max-h-[32rem]",
},
xl: {
base: "max-w-xl max-h-[36rem]",
},
"2xl": {
base: "max-w-2xl max-h-[42rem]",
},
"3xl": {
base: "max-w-3xl max-h-[48rem]",
},
"4xl": {
base: "max-w-4xl max-h-[56rem]",
},
"5xl": {
base: "max-w-5xl max-h-[64rem]",
},
full: {
base: "max-w-full max-h-full h-[100dvh] !rounded-none",
},
},
placement: {
top: {
base: "inset-x-0 top-0 max-w-[none] rounded-t-none",
},
right: {
base: "inset-y-0 right-0 max-h-[none] rounded-r-none",
},
bottom: {
base: "inset-x-0 bottom-0 max-w-[none] rounded-b-none",
},
left: {
base: "inset-y-0 left-0 max-h-[none] rounded-l-none",
},
},
},
});
// ...
export {modal, drawer}; This is all the code of the Drawer component. Usage: import {
Modal,
Drawer,
ModalContent,
ModalHeader,
ModalBody,
ModalFooter,
ModalProps,
useDisclosure,
} from "@nextui-org/modal";
const App = () => {
const {isOpen, onOpen, onOpenChange} = useDisclosure({defaultOpen: false});
return (
<>
<Button onPress={onOpen}>Open Modal</Button>
<Drawer
isOpen={isOpen}
onOpenChange={onOpenChange}
scrollBehavior="inside"
size="lg"
placement="right"
// classNames={{
// base: "w-[378px]",
// }}
>
<ModalContent>
{(onClose) => (
<>
<ModalHeader className="flex flex-col gap-1">Log in</ModalHeader>
<ModalBody>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam pulvinar risus non
risus hendrerit venenatis. Pellentesque sit amet hendrerit risus, sed porttitor
quam.
</p>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam pulvinar risus non
risus hendrerit venenatis. Pellentesque sit amet hendrerit risus, sed porttitor
quam.
</p>
<p>
Magna exercitation reprehenderit magna aute tempor cupidatat consequat elit dolor
adipisicing. Mollit dolor eiusmod sunt ex incididunt cillum quis. Velit duis sit
officia eiusmod Lorem aliqua enim laboris do dolor eiusmod. Et mollit incididunt
nisi consectetur esse laborum eiusmod pariatur proident Lorem eiusmod et. Culpa
deserunt nostrud ad veniam.
</p>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam pulvinar risus non
risus hendrerit venenatis. Pellentesque sit amet hendrerit risus, sed porttitor
quam. Magna exercitation reprehenderit magna aute tempor cupidatat consequat elit
dolor adipisicing. Mollit dolor eiusmod sunt ex incididunt cillum quis. Velit duis
sit officia eiusmod Lorem aliqua enim laboris do dolor eiusmod. Et mollit
incididunt nisi consectetur esse laborum eiusmod pariatur proident Lorem eiusmod
et. Culpa deserunt nostrud ad veniam.
</p>
<p>
Mollit dolor eiusmod sunt ex incididunt cillum quis. Velit duis sit officia
eiusmod Lorem aliqua enim laboris do dolor eiusmod. Et mollit incididunt nisi
consectetur esse laborum eiusmod pariatur proident Lorem eiusmod et. Culpa
deserunt nostrud ad veniam. Lorem ipsum dolor sit amet, consectetur adipiscing
elit. Nullam pulvinar risus non risus hendrerit venenatis. Pellentesque sit amet
hendrerit risus, sed porttitor quam. Magna exercitation reprehenderit magna aute
tempor cupidatat consequat elit dolor adipisicing. Mollit dolor eiusmod sunt ex
incididunt cillum quis. Velit duis sit officia eiusmod Lorem aliqua enim laboris
do dolor eiusmod. Et mollit incididunt nisi consectetur esse laborum eiusmod
pariatur proident Lorem eiusmod et. Culpa deserunt nostrud ad veniam.
</p>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam pulvinar risus non
risus hendrerit venenatis. Pellentesque sit amet hendrerit risus, sed porttitor
quam.
</p>
<p>
Magna exercitation reprehenderit magna aute tempor cupidatat consequat elit dolor
adipisicing. Mollit dolor eiusmod sunt ex incididunt cillum quis. Velit duis sit
officia eiusmod Lorem aliqua enim laboris do dolor eiusmod. Et mollit incididunt
nisi consectetur esse laborum eiusmod pariatur proident Lorem eiusmod et. Culpa
deserunt nostrud ad veniam.
</p>
<p>
Mollit dolor eiusmod sunt ex incididunt cillum quis. Velit duis sit officia
eiusmod Lorem aliqua enim laboris do dolor eiusmod. Et mollit incididunt nisi
consectetur esse laborum eiusmod pariatur proident Lorem eiusmod et. Culpa
deserunt nostrud ad veniam. Lorem ipsum dolor sit amet, consectetur adipiscing
elit. Nullam pulvinar risus non risus hendrerit venenatis. Pellentesque sit amet
hendrerit risus, sed porttitor quam. Magna exercitation reprehenderit magna aute
tempor cupidatat consequat elit dolor adipisicing. Mollit dolor eiusmod sunt ex
incididunt cillum quis. Velit duis sit officia eiusmod Lorem aliqua enim laboris
do dolor eiusmod. Et mollit incididunt nisi consectetur esse laborum eiusmod
pariatur proident Lorem eiusmod et. Culpa deserunt nostrud ad veniam.
</p>
</ModalBody>
<ModalFooter>
<Button color="danger" variant="flat" onPress={onClose}>
Close
</Button>
<Button color="primary" onPress={onClose}>
Sign in
</Button>
</ModalFooter>
</>
)}
</ModalContent>
</Drawer>
</>
);
}; I tested it locally and it works fine. I don't know if this way of supporting Drawer components meets your expectations. Please feel free to let me know if you have any questions. |
Hey @1111mp why did you close this?, I'm still reviewing your suggestion, you're on the right track |
I'm very sorry that I didn't reply in time. I've rearranged the code locally and added a But I found that previous commit records may pollute the main branch in the future, so I decided to reopen a PR #2223. Please understand. This way you can quickly synchronize your code and perform testing and evaluation. |
📝 Description
Added Drawer component.
Learned about some user feature requests from #2134 [Feature Request] Some Components Feature Suggestions, so I started to implement them from the simplest components (Because it can almost reuse Modal’s design and code).
⛳️ Current behavior (updates)
There is currently no support for the Drawer component.
🚀 New behavior
We can have the Drawer component.
💣 Is this a breaking change (Yes/No):
No. Supports the new Drawer component, which will not have any impact on other components.
📝 Additional Information
There is currently some work yet to be completed, such as Drawer documentation and usage examples. Because I don’t know whether such code complies with the specifications of the warehouse, I initiated a PR in advance to confirm this. If all goes well I will continue with the rest of the work.
Feel free to point out my questions at any time. Of course, if you already have Drawer-related implementation plans or other questions, please let me know and I will close this PR. Thank you.