+
+ Open Modal
+
+
+
+
+ Create Username
+
+
+ Enter a unique name for your token to differentiate it from
+ other tokens and then select the scope.
+
+
+
+
+
+
+
+ Cancel
+
+ Submit
+
+
+
+
+
+ );
+};
+
+export default Usage;
diff --git a/apps/www/components/preview/index.tsx b/apps/www/components/preview/index.tsx
index cf81028..ca12b50 100644
--- a/apps/www/components/preview/index.tsx
+++ b/apps/www/components/preview/index.tsx
@@ -27,6 +27,7 @@ import {
import { BadgePreview } from "../badgePreview";
import Tabspreview from "../tabs";
+import { default as ModalPreview } from "./Modal/preview";
export default {
button: (
@@ -163,4 +164,9 @@ export default {
),
+ modal: (
+
+
+
+ ),
} as Record;
diff --git a/apps/www/content/docs/cli.mdx b/apps/www/content/docs/cli.mdx
index 07481fb..803e2f2 100644
--- a/apps/www/content/docs/cli.mdx
+++ b/apps/www/content/docs/cli.mdx
@@ -1,5 +1,5 @@
---
-title: Cli
+title: CLI
description: The CLI is a command-line interface that allows you to add components to your project.
---
diff --git a/apps/www/content/docs/components/modal.mdx b/apps/www/content/docs/components/modal.mdx
new file mode 100644
index 0000000..bbabba9
--- /dev/null
+++ b/apps/www/content/docs/components/modal.mdx
@@ -0,0 +1,550 @@
+---
+title: Modal
+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";
+import Usage from "../../../components/preview/Modal/usage.tsx";
+import Trigger from "../../../components/preview/Modal/trigger.tsx";
+import SingleButton from "../../../components/preview/Modal/singleButton.tsx";
+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";
+
+## Installation
+
+
+
+
+
+```bash
+npx ruru-ui-cli@latest add modal
+```
+
+
+```bash
+pnpm dlx ruru-ui-cli@latest add modal
+```
+
+
+```bash
+npx ruru-ui-cli@latest add modal
+```
+
+
+```bash
+bunx --bun ruru-ui-cli@latest add modal
+```
+
+
+
+
+
+```package-install
+npm install ruru-ui@latest
+```
+
+
+
+
+## Usage
+
+Here is an example of how to use the `Modal` component.
+
+
+
+
+
+
+```tsx
+"use client";
+
+import React, { useState } from "react";
+import { Input } from "ruru-ui/components/input";
+import Modal, { ModalProvider } from "ruru-ui/components/modal";
+
+const Usage = () => {
+ const [isLoading, setIsLoading] = useState(false);
+
+ const handleSubmit = async () => {
+ setIsLoading(true);
+
+ await new Promise((resolve) => setTimeout(resolve, 2000));
+ setIsLoading(false);
+ };
+
+ return (
+
+
+ Open Modal
+
+
+
+
+ Create Username
+
+
+ Enter a unique name for your token to differentiate it from
+ other tokens and then select the scope.
+
+
+
+
+
+
+
+ Cancel
+
+ Submit
+
+
+
+
+
+ );
+};
+
+export default Usage;
+```
+
+
+
+
+## Example
+
+### Modal with Trigger
+
+The `Modal` component can be used with a custom trigger button.
+
+
+
+
+
+
+```tsx
+"use client";
+
+import React from "react";
+import { Button } from "ruru-ui/components/button";
+import { Input } from "ruru-ui/components/input";
+import Modal, { ModalProvider } from "ruru-ui/components/modal";
+
+const TriggerDemo = () => {
+ return (
+
+
+
+
+
+
+
+
+ Custom Trigger
+
+
+ This modal opens with a custom trigger button.
+
+
+
+
+
+
+
+ Cancel
+ Submit
+
+
+
+ );
+};
+
+export default TriggerDemo;
+```
+
+
+
+
+### Single button
+
+The `Modal` component can be used with a single button.
+
+
+
+
+
+
+```tsx
+"use client";
+
+import React from "react";
+import { Button } from "ruru-ui/components/button";
+import { Input } from "ruru-ui/components/input";
+import Modal, { ModalProvider } from "ruru-ui/components/modal";
+
+const SingleButton = () => {
+ return (
+
+
+
+
+
+
+
+
+ Custom Trigger
+
+
+ This modal opens with a custom trigger button.
+
+
+
+
+
+
+
+ Cancel
+
+
+
+ );
+};
+
+export default SingleButton;
+```
+
+
+
+### Disabled actions
+
+The `Modal` component can be used with disabled actions.
+
+
+
+
+
+
+```tsx
+"use client";
+
+import React from "react";
+import { Button } from "ruru-ui/components/button";
+import { Input } from "ruru-ui/components/input";
+import Modal, { ModalProvider } from "ruru-ui/components/modal";
+
+const Disabled = () => {
+ return (
+
+
+
+
+
+
+
+
+ Custom Trigger
+
+
+ This modal opens with a custom trigger button.
+
+
+
+
+
+
+
+ Cancel
+ Submit
+
+
+
+ );
+};
+
+export default Disabled;
+```
+
+
+
+### Modal with custom width
+
+The `Modal` component can be used with a custom width.
+
+
+
+
+
+
+```tsx
+"use client";
+
+import React from "react";
+import { Button } from "ruru-ui/components/button";
+import { Input } from "ruru-ui/components/input";
+import Modal, { ModalProvider } from "ruru-ui/components/modal";
+
+const CustomWidth = () => {
+ return (
+
+
+
+
+
+
+
+
+ Custom Width
+
+
+ This modal opens with a Custom Width button.
+
+
+
+
+
+
+
+ Cancel
+
+
+
+ );
+};
+
+export default CustomWidth;
+```
+
+
+
+
+
+
+
+
+```tsx
+"use client";
+
+import React from "react";
+import { Button } from "ruru-ui/components/button";
+import { Input } from "ruru-ui/components/input";
+import Modal, { ModalProvider } from "ruru-ui/components/modal";
+
+const CustomWidth2 = () => {
+ return (
+
+
+
+
+
+
+
+
+ Custom Width
+
+
+ This modal opens with a Custom Width button.
+
+
+
+
+
+
+
+
+ Cancel
+
+ Submit
+
+
+
+ );
+};
+
+export default CustomWidth2;
+```
+
+
+
+### Preview Component
+
+The component that you see on preview
+
+
+
+
+
+
+```tsx
+"use client";
+
+import React, { useState } from "react";
+import Modal, { ModalProvider } from "ruru-ui/components/modal";
+import { Input } from "ruru-ui/components/input";
+
+const Preview = () => {
+ const [isLoading, setIsLoading] = useState(false);
+ const [status, setStatus] = useState(false);
+
+ const handleSubmit = async () => {
+ setIsLoading(true);
+
+ await new Promise((resolve) => setTimeout(resolve, 2000));
+ setStatus(true);
+ setIsLoading(false);
+
+ await new Promise((resolve) => setTimeout(resolve, 500));
+
+ setStatus(false);
+ };
+
+ return (
+
+
+ Deploy
+
+
+
+
+ Deploy to production
+
+
+ Deploy your site to production by clicking the button below.
+
+
+
+
+
+
+
+ Cancel
+
+ {status ? (
+
+ ) : (
+ "Deploy"
+ )}
+
+
+
+
+
+ );
+};
+
+export default Preview;
+```
+
+
+
+## Props
+
+Here's how the props table would look for the `Modal` component, formatted in the same style:
+
+## Props
+
+### 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. |
+
+### ModalAction
+
+| Name | Type | Default | Description |
+| ----------------- | --------------------------------- | ----------- | -------------------------------------------------------------------------------------- |
+| **fullWidth** | **boolean** | `false` | Determines if the action button should take the full width. |
+| **onClick** | **() =\> void \| Promise\** | `undefined` | The function to call when the user clicks the action. |
+
+### Trigger
+
+| Name | Type | Default | Description |
+| ----------------- | --------------------------------- | ----------- | -------------------------------------------------------------------------------------- |
+| **children** | **ReactNode** | `undefined` | The children of the Modal component. |
+| **onClick** | **() => void** | `undefined` | The function to call when the user clicks the trigger. |
+| **asChild** | **boolean** | `false` | Render as a child component. |
+
+### DivProps
+
+| Name | Type | Default | Description |
+| ----------------- | --------------------------------- | ----------- | -------------------------------------------------------------------------------------- |
+| **className** | **string** | `""` | Additional class names for the container. |
+| **children** | **ReactNode** | `undefined` | The children of the component. |
+
+### PTagProps
+
+| Name | Type | Default | Description |
+| ----------------- | --------------------------------- | ----------- | -------------------------------------------------------------------------------------- |
+| **className** | **string** | `""` | Additional class names for the paragraph element. |
+| **children** | **ReactNode** | `undefined` | The children of the paragraph element. |
+
diff --git a/apps/www/content/docs/components/textarea.mdx b/apps/www/content/docs/components/textarea.mdx
index 0c06252..f794464 100644
--- a/apps/www/content/docs/components/textarea.mdx
+++ b/apps/www/content/docs/components/textarea.mdx
@@ -11,38 +11,38 @@ import { Tabs as Rutabs, Tab as Rutab } from "ruru-ui/components/tabs";
## Installation
-
-
-
- ```bash
- npx ruru-ui-cli@latest add textarea
- ```
-
-
- ```bash
- pnpm dlx ruru-ui-cli@latest add textarea
- ```
-
-
- ```bash
- npx ruru-ui-cli@latest add textarea
- ```
-
-
- ```bash
- bunx --bun ruru-ui-cli@latest add textarea
- ```
-
-
+
+
+
+```bash
+npx ruru-ui-cli@latest add textarea
+```
+
+
+```bash
+pnpm dlx ruru-ui-cli@latest add textarea
+```
+
+
+```bash
+npx ruru-ui-cli@latest add textarea
+```
+
+
+```bash
+bunx --bun ruru-ui-cli@latest add textarea
+```
+
+
-
-
+
+
- ```package-install
- npm install ruru-ui@latest
- ```
+```package-install
+npm install ruru-ui@latest
+```
-
+
## Usage
diff --git a/apps/www/public/registry/components/modal.json b/apps/www/public/registry/components/modal.json
index 7fa6bd3..9389d04 100644
--- a/apps/www/public/registry/components/modal.json
+++ b/apps/www/public/registry/components/modal.json
@@ -3,7 +3,7 @@
"files": [
{
"name": "modal.tsx",
- "content": "import React, {\n useState,\n useContext,\n useCallback,\n ReactNode,\n createContext,\n useEffect,\n} from \"react\";\nimport {\n AnimatePresence,\n ForwardRefComponent,\n HTMLMotionProps,\n motion,\n} from \"framer-motion\";\nimport { cn } from \"@/utils/cn\";\nimport { Button, ButtonProps } from \"./button\";\n\n\nexport interface ModalContextProps {\n \n isOpen: boolean;\n \n openModal: () => void;\n \n closeModal: () => void;\n}\n\n\nexport interface ModalProps\n extends Partial>> {\n \n children: ReactNode;\n \n onClickOutside?: () => void;\n}\n\n\nexport interface ModalActionProps extends ButtonProps {\n \n fullWidth?: boolean;\n \n onClick?: () => void | Promise;\n}\n\n\nexport interface TriggerProps extends ButtonProps {\n \n children: ReactNode;\n \n onClick?: () => void;\n \n asChild?: boolean;\n}\n\n\nexport interface DivProps\n extends React.DetailedHTMLProps<\n React.HTMLAttributes,\n HTMLDivElement\n > {}\n\n\nconst ModalContext = createContext(undefined);\n\n\nexport const ModalProvider = ({\n children,\n}: {\n children: ReactNode;\n}): React.ReactElement => {\n const [isOpen, setIsOpen] = useState(false);\n\n const openModal = useCallback(() => setIsOpen(true), []);\n const closeModal = useCallback(() => setIsOpen(false), []);\n\n return (\n \n {children}\n \n );\n};\n\n\nexport const useModal = (): ModalContextProps => {\n const context = useContext(ModalContext);\n if (!context) {\n throw new Error(\"useModal must be used within a ModalProvider\");\n }\n return context;\n};\n\n\nconst Modal = ({\n children,\n onClickOutside,\n ...props\n}: ModalProps): React.ReactElement => {\n const { isOpen, closeModal } = useModal();\n\n useEffect(() => {\n const handleEscape = (event: KeyboardEvent) => {\n if (event.key === \"Escape\") {\n closeModal();\n }\n };\n\n if (isOpen) {\n document.addEventListener(\"keydown\", handleEscape);\n } else {\n document.removeEventListener(\"keydown\", handleEscape);\n }\n\n return () => document.removeEventListener(\"keydown\", handleEscape);\n }, [isOpen, closeModal]);\n\n const modalVariants = {\n hidden: {\n opacity: 0,\n y: -50,\n rotateX: \"0deg\",\n transition: { duration: 0.15 },\n },\n visible: {\n opacity: 1,\n y: 0,\n rotateX: \"0deg\",\n transition: { duration: 0.15 },\n },\n exit: {\n opacity: 0,\n y: -50,\n rotateX: \"-10deg\",\n transition: { duration: 0.15 },\n },\n };\n\n return (\n \n {isOpen && (\n \n e.stopPropagation()}\n variants={modalVariants}\n initial=\"hidden\"\n animate=\"visible\"\n exit=\"exit\"\n >\n {children}\n \n \n )}\n \n );\n};\n\n\nModal.Trigger = ({\n children,\n onClick,\n asChild = false,\n}: TriggerProps): React.ReactElement => {\n const { openModal } = useModal();\n\n const handleClick = () => {\n openModal();\n if (onClick) {\n onClick();\n }\n };\n\n if (asChild) {\n return (\n