Skip to content

Commit

Permalink
Merge pull request #81 from ruru-m07/enhance-modal-animations
Browse files Browse the repository at this point in the history
feat(modal): enhance modal component with multiple animation variants
  • Loading branch information
ruru-m07 authored Oct 20, 2024
2 parents 894b8b4 + 36a4446 commit 8c6833a
Show file tree
Hide file tree
Showing 6 changed files with 407 additions and 34 deletions.
33 changes: 32 additions & 1 deletion apps/www/app/playground/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ import {
SelectSeparator,
selectAnimationVariants,
} from "ruru-ui/components/select";
import Modal, { ModalProvider } from "ruru-ui/components/modal";
import Modal, { ModalProvider, modalVariants } from "ruru-ui/components/modal";
import { Dropzone } from "ruru-ui/components/dropzone";
import AdvanceDropzone from "@/components/preview/dropzone/advanceDropzone";
import StackPlayground from "@/components/stackPlayground";
Expand Down Expand Up @@ -610,6 +610,37 @@ const Playground = () => {
</ModalProvider>
</Card>

{(Object.keys(modalVariants) as Array<keyof typeof modalVariants>).map(
(variantKey) => (
<Card key={variantKey}>
<ModalProvider>
<Modal.Trigger>Open {variantKey} Modal</Modal.Trigger>
<Modal animationVariant={variantKey}>
<Modal.Body>
<Modal.Header>
<Modal.Title>Create Username</Modal.Title>
<Modal.Subtitle>
Enter a unique name for your token to differentiate it
from other tokens and then select the scope.
</Modal.Subtitle>
</Modal.Header>
<Modal.Content>
<Input
label="username"
placeholder="enter your username."
/>
</Modal.Content>
</Modal.Body>
<Modal.Actions>
<Modal.Close variant="secondary">Cancel</Modal.Close>
<Modal.Action onClick={handleSubmit}>Submit</Modal.Action>
</Modal.Actions>
</Modal>
</ModalProvider>
</Card>
),
)}

<Card className="p-10">
<Dropzone onDrop={(acceptedFiles) => console.log(acceptedFiles)} />
</Card>
Expand Down
94 changes: 94 additions & 0 deletions apps/www/components/preview/Modal/modalAnimation.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
"use client";

import React, { useState } from "react";
import { Stack } from "ruru-ui/components/stack";
import {
Select,
SelectGroup,
SelectValue,
SelectTrigger,
SelectContent,
SelectLabel,
SelectItem,
SelectSeparator,
} from "ruru-ui/components/select";
import Modal, { ModalProvider, modalVariants } from "ruru-ui/components/modal";
import { Input } from "ruru-ui/components/input";
import { Spinner } from "ruru-ui/components/spinner";

const ModalAnimation = (): JSX.Element => {
const [selectedVariant, setSelectedVariant] = useState<string>("default");
const [submissionStatus, setSubmissionStatus] = useState<
"idle" | "loading" | "success" | "error"
>("idle");

const handleSubmit = async () => {
setSubmissionStatus("loading");
try {
// Your submit logic here
console.log(`Submitting with variant: ${selectedVariant}`);
// Simulate an API call or any async operation
await new Promise((resolve) => setTimeout(resolve, 1000));
setSubmissionStatus("success");
} catch (error) {
console.error("Submission failed:", error);
setSubmissionStatus("error");
}
};

return (
<Stack direction={"column"} justify={"center"} align={"center"} gap={20}>
<Select
onValueChange={(e) => setSelectedVariant(e)}
defaultValue="default"
>
<SelectTrigger className="w-[180px]">
<SelectValue placeholder="Select a animation variants" />
</SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectLabel>variants</SelectLabel>
<SelectSeparator />
{(
Object.keys(modalVariants) as Array<keyof typeof modalVariants>
).map((variantKey) => (
<SelectItem key={variantKey} value={variantKey}>
{variantKey}
</SelectItem>
))}
</SelectGroup>
</SelectContent>
</Select>
<ModalProvider>
<Modal.Trigger>Open {selectedVariant} Modal</Modal.Trigger>
<Modal animationVariant={selectedVariant as keyof typeof modalVariants}>
<Modal.Body>
<Modal.Header>
<Modal.Title>Create Username</Modal.Title>
<Modal.Subtitle>
Enter a unique name for your token to differentiate it from
other tokens and then select the scope.
</Modal.Subtitle>
</Modal.Header>
<Modal.Content>
<Input label="username" placeholder="enter your username." />
</Modal.Content>
</Modal.Body>
<Modal.Actions>
<Modal.Close variant="secondary">Cancel</Modal.Close>
<Modal.Action
disabled={submissionStatus === "loading"}
variant={submissionStatus === "loading" ? "secondary" : "default"}
onClick={handleSubmit}
>
{submissionStatus === "loading" && <Spinner className="mr-2" />}{" "}
Submit
</Modal.Action>
</Modal.Actions>
</Modal>
</ModalProvider>
</Stack>
);
};

export default ModalAnimation;
103 changes: 94 additions & 9 deletions apps/www/content/docs/components/modal.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ description: The Modal component is used to display content in a modal dialog.
preview: modal
---


import Modal, { ModalProvider } from "ruru-ui/components/modal";
import { Tab, Tabs } from "fumadocs-ui/components/tabs";
import { Tabs as Rutabs, Tab as Rutab } from "ruru-ui/components/tabs";
Expand All @@ -15,6 +14,7 @@ import Disabled from "../../../components/preview/Modal/disabled.tsx";
import CustomWidth from "../../../components/preview/Modal/customWidth.tsx";
import CustomWidth2 from "../../../components/preview/Modal/customWidth2.tsx";
import Preview from "../../../components/preview/Modal/preview.tsx";
import ModalAnimation from "../../../components/preview/Modal/modalAnimation";

## Installation

Expand Down Expand Up @@ -125,7 +125,6 @@ export default Usage;
</Tab>
</Tabs>


## Example

### Modal with Trigger
Expand Down Expand Up @@ -185,7 +184,6 @@ export default TriggerDemo;
</Tab>
</Tabs>


### Single button

The `Modal` component can be used with a single button.
Expand Down Expand Up @@ -527,18 +525,105 @@ export default Preview;
</Tab>
</Tabs>

## Props
## Animation Variants

Here's how the props table would look for the `Modal` component, formatted in the same style:
The `Modal` component supports multiple animation variants for opening and closing. You can set the animation variant by passing the `animationVariant` prop to the `Modal` component.

<Tabs items={["Preview", "Code"]}>
<Tab className={"flex justify-center"} value="Preview">
<ModalAnimation />
</Tab>
<Tab className={"-mt-8"} value="Code">
```tsx
"use client";

import React, { useState } from "react";
import { Stack } from "ruru-ui/components/stack";
import {
Select,
SelectGroup,
SelectValue,
SelectTrigger,
SelectContent,
SelectLabel,
SelectItem,
SelectSeparator,
} from "ruru-ui/components/select";
import Modal, { ModalProvider, modalVariants } from "ruru-ui/components/modal";
import { Input } from "ruru-ui/components/input";

const ModalAnimation = (): React.ReactNode => {
const [selectedVariant, setSelectedVariant] = useState<string>("default");

const handleSubmit = async () => {
// Your submit logic here
console.log("Submitted");
// Simulate an API call or any async operation
await new Promise((resolve) => setTimeout(resolve, 1000));
};

return (
<Stack direction={"column"} justify={"center"} align={"center"} gap={20}>
<Select
onValueChange={(e) => setSelectedVariant(e)}
defaultValue="default"
>
<SelectTrigger className="w-[180px]">
<SelectValue placeholder="Select a animation variants" />
</SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectLabel>variants</SelectLabel>
<SelectSeparator />
{(
Object.keys(modalVariants) as Array<keyof typeof modalVariants>
).map((variantKey, index) => (
<SelectItem value={variantKey}>{variantKey}</SelectItem>
))}
</SelectGroup>
</SelectContent>
</Select>
<ModalProvider>
<Modal.Trigger>Open {selectedVariant} Modal</Modal.Trigger>
<Modal animationVariant={selectedVariant as keyof typeof modalVariants}>
<Modal.Body>
<Modal.Header>
<Modal.Title>Create Username</Modal.Title>
<Modal.Subtitle>
Enter a unique name for your token to differentiate it from
other tokens and then select the scope.
</Modal.Subtitle>
</Modal.Header>
<Modal.Content>
<Input label="username" placeholder="enter your username." />
</Modal.Content>
</Modal.Body>
<Modal.Actions>
<Modal.Close variant="secondary">Cancel</Modal.Close>
<Modal.Action onClick={handleSubmit}>Submit</Modal.Action>
</Modal.Actions>
</Modal>
</ModalProvider>
</Stack>
);
};

export default ModalAnimation;
```
</Tab>
</Tabs>

## Props

Here's how the props table would look for the `Modal` component, formatted in the same style:

### Modal

| Name | Type | Default | Description |
| ----------------- | --------------------------------- | ----------- | -------------------------------------------------------------------------------------- |
| **children** | **ReactNode** | `undefined` | The children of the Modal component. |
| **onClickOutside**| **() => void** | `undefined` | The function to call when the user clicks outside the modal. |
| Name | Type | Default | Description |
| -------------------- | ----------------------------------------------------------------------------------------------------------------------------------- | ----------- | ----------------------------------------------------------------------------------------------------------------- |
| **children** | **ReactNode** | `undefined` | The children of the Modal component. |
| **onClickOutside** | **() => void** | `undefined` | The function to call when the user clicks outside the modal. |
| **animationVariant** | **"default" \| "fade" \| "zoom" \| "scaleBounce" \| "slideUp" \| "slideDown" \| "slideRight" \| "slideLeft" \| "flip" \| "rotate"** | `"default"` | Specifies the animation style for opening and closing the modal. Each variant provides a different visual effect. |

### ModalAction

Expand Down
Loading

0 comments on commit 8c6833a

Please sign in to comment.