npm package: @leowjy/modal_js
Description: A reusable modal component for react applications.
Latest version: 1.2.2

# MODAL FORM

A reusable, customizable modal component library for React applications with built-in button components and multi-page support.

## Features

- **Pre-styled Button Component** - Multiple button types (primary, secondary, danger, dashed)
- **Flexible Modal Component** - Customizable modal with smooth animations
- **Multi-page Support** - Create wizards and multi-step forms easily
- **Editable Title** - Allow users to edit modal title inline with double-click or edit icon
- **Toast Notifications** - Beautiful toast notifications with multiple types and positions
- **TypeScript Support** - Fully typed for better developer experience
- **Smooth Animations** - Fade-in/fade-out and pop-in/pop-out effects
- **Custom Footer** - Full control over modal footer buttons

## Installation

```bash
npm install @leowjy/modal_js
```

## Peer Dependencies

This package requires the following peer dependencies:

- React >= 18
- React-DOM >= 18

## Components

### SelfButton

A customizable button component with multiple styles.

#### Props

| Prop       | Type                                               | Default     | Description                    |
| ---------- | -------------------------------------------------- | ----------- | ------------------------------ |
| `type`     | `"primary" \| "secondary" \| "danger" \| "dashed"` | `"primary"` | Button style type              |
| `onClick`  | `() => void`                                       | -           | Click handler function         |
| `children` | `React.ReactNode`                                  | -           | Button content                 |
| `disabled` | `boolean`                                          | `false`     | Whether the button is disabled |

#### Example

```tsx
import { SelfButton } from "@leowjy/modal_js";
import "@leowjy/modal_js/dist/index.css";

function App() {
  return (
    <div>
      <SelfButton type="primary" onClick={() => alert("Clicked!")}>
        Click Me
      </SelfButton>

      <SelfButton type="danger" onClick={() => console.log("Delete")}>
        Delete
      </SelfButton>
    </div>
  );
}
```

### ModalForm

A flexible modal component with support for single and multi-page content.

#### Props

| Prop            | Type                         | Default | Description                            |
| --------------- | ---------------------------- | ------- | -------------------------------------- |
| `title`         | `string`                     | -       | Modal title (required)                 |
| `open`          | `boolean`                    | -       | Controls modal visibility              |
| `onOk`          | `() => void`                 | -       | Handler for OK button click            |
| `onCancel`      | `() => void`                 | -       | Handler for Cancel button click        |
| `onClose`       | `() => void`                 | -       | Handler for modal close                |
| `footer`        | `ReactNode \| ReactNode[]`   | -       | Custom footer content                  |
| `children`      | `React.ReactNode`            | -       | Modal content (required)               |
| `multi`         | `boolean`                    | `false` | Enable multi-page mode with navigation |
| `titleEdit`     | `boolean`                    | `false` | Enable inline title editing            |
| `onTitleUpdate` | `(newTitle: string) => void` | -       | Callback when title is updated         |
| `width`         | `number \| string`           | -       | Modal width                            |

#### Basic Example

```tsx
import { useState } from "react";
import { ModalForm, SelfButton } from "@leowjy/modal_js";
import "@leowjy/modal_js/dist/index.css";

function App() {
  const [isOpen, setIsOpen] = useState(false);

  return (
    <div>
      <SelfButton onClick={() => setIsOpen(true)}>Open Modal</SelfButton>

      <ModalForm
        title="My Modal"
        open={isOpen}
        onOk={() => {
          console.log("OK clicked");
          setIsOpen(false);
        }}
        onCancel={() => setIsOpen(false)}
      >
        <p>This is the modal content!</p>
      </ModalForm>
    </div>
  );
}
```

#### Multi-Page Modal Example

Use the `ModalForm.Page` component to create multi-step modals:

```tsx
import { useState } from "react";
import { ModalForm, SelfButton } from "@leowjy/modal_js";
import "@leowjy/modal_js/dist/index.css";

function App() {
  const [isOpen, setIsOpen] = useState(false);

  return (
    <div>
      <SelfButton onClick={() => setIsOpen(true)}>Open Wizard</SelfButton>

      <ModalForm
        title="Multi-Step Form"
        open={isOpen}
        multi={true}
        onCancel={() => setIsOpen(false)}
        footer={<SelfButton onClick={() => setIsOpen(false)}>Close</SelfButton>}
      >
        <ModalForm.Page>
          <h3>Step 1</h3>
          <p>First page content</p>
        </ModalForm.Page>

        <ModalForm.Page>
          <h3>Step 2</h3>
          <p>Second page content</p>
        </ModalForm.Page>

        <ModalForm.Page>
          <h3>Step 3</h3>
          <p>Final page content</p>
        </ModalForm.Page>
      </ModalForm>
    </div>
  );
}
```

#### Custom Footer Example

```tsx
<ModalForm
  title="Custom Footer Modal"
  open={isOpen}
  footer={
    <>
      <SelfButton type="danger" onClick={() => console.log("Delete")}>
        Delete
      </SelfButton>
      <SelfButton type="secondary" onClick={() => setIsOpen(false)}>
        Close
      </SelfButton>
      <SelfButton type="primary" onClick={() => console.log("Save")}>
        Save
      </SelfButton>
    </>
  }
>
  <p>Modal content with custom footer buttons</p>
</ModalForm>
```

#### Editable Title Example

Enable users to edit the modal title inline by double-clicking or using the edit icon:

```tsx
import { useState } from "react";
import { ModalForm, SelfButton } from "@leowjy/modal_js";
import "@leowjy/modal_js/dist/index.css";

function App() {
  const [isOpen, setIsOpen] = useState(false);
  const [modalTitle, setModalTitle] = useState("Editable Modal Title");

  return (
    <div>
      <SelfButton onClick={() => setIsOpen(true)}>Open Modal</SelfButton>

      <ModalForm
        title={modalTitle}
        open={isOpen}
        titleEdit={true}
        onTitleUpdate={(newTitle) => {
          console.log("Title updated to:", newTitle);
          setModalTitle(newTitle);
        }}
        onCancel={() => setIsOpen(false)}
      >
        <p>Double-click the title or click the edit icon to change it!</p>
      </ModalForm>
    </div>
  );
}
```

## Button Types

The `SelfButton` component supports four button types:

- **primary** - Main action button (default)
- **secondary** - Secondary action button
- **danger** - Destructive action button
- **dashed** - Outlined/bordered button style

---

## Toast Notifications

A flexible toast notification system with multiple types and customizable positions.

### Setup

Wrap your application with the `ToastProvider`:

```tsx
import { ToastProvider } from "@leowjy/modal_js";
import "@leowjy/modal_js/dist/index.css";

function App() {
  return (
    <ToastProvider>
      <YourAppComponents />
    </ToastProvider>
  );
}
```

### Using the useAppToast Hook

The `useAppToast` hook provides convenient methods for showing toast notifications:

```tsx
import { useAppToast } from "@leowjy/modal_js";

function MyComponent() {
  const toast = useAppToast();

  return (
    <div>
      <button onClick={() => toast.success("Operation successful!")}>
        Show Success
      </button>

      <button onClick={() => toast.error("Something went wrong!")}>
        Show Error
      </button>

      <button onClick={() => toast.info("Here's some information")}>
        Show Info
      </button>

      <button onClick={() => toast.warning("Warning: Please be careful")}>
        Show Warning
      </button>
    </div>
  );
}
```

### Toast Types

The toast system supports the following predefined types:

- **success** - Green toast with checkmark icon
- **error** - Red toast with error icon
- **info** - Blue toast with info icon
- **warning** - Yellow/orange toast with warning icon
- **custom** - Fully customizable toast with your own styling

### Toast Options

All toast methods accept an optional `options` object:

| Option     | Type        | Default       | Description                                  |
| ---------- | ----------- | ------------- | -------------------------------------------- |
| `duration` | `number`    | `3000`        | Duration in milliseconds before auto-dismiss |
| `position` | `POSITIONS` | `"top-right"` | Position of the toast on screen              |

#### Available Positions

- `top-right`
- `top-left`
- `top-center`
- `bottom-right`
- `bottom-left`
- `bottom-center`

### Examples

#### Basic Toast with Options

```tsx
import { useAppToast } from "@leowjy/modal_js";

function MyComponent() {
  const toast = useAppToast();

  const handleSave = () => {
    toast.success("Data saved successfully!", {
      duration: 5000,
      position: "bottom-right",
    });
  };

  return <button onClick={handleSave}>Save</button>;
}
```

#### Toast with JSX Content

```tsx
toast.error(
  <div>
    <strong>Error!</strong> Something went wrong.
  </div>,
  { duration: 4000, position: "top-center" },
);
```

#### Custom Toast

Create fully customized toasts with your own styling:

```tsx
toast.custom(
  <div>
    <h4>Custom Toast</h4>
    <p>This is a custom toast message.</p>
  </div>,
  {
    className: "my-custom-toast",
    style: {
      backgroundColor: "#333",
      color: "#fff",
      borderRadius: "8px",
      padding: "16px",
    },
    duration: 4000,
    position: "top-center",
  },
);
```

### Custom Toast Options

For custom toasts, you can use these additional options:

| Option      | Type                  | Description                      |
| ----------- | --------------------- | -------------------------------- |
| `className` | `string`              | Additional CSS class for styling |
| `style`     | `React.CSSProperties` | Inline styles                    |
| `duration`  | `number`              | Duration in milliseconds         |
| `position`  | `POSITIONS`           | Position on screen               |

### Using addToast Directly

You can also use the `addToast` function directly from the `useToast` hook:

```tsx
import { useToast } from "@leowjy/modal_js";

function MyComponent() {
  const { addToast } = useToast();

  const showNotification = () => {
    addToast("This is a success message", "success", {
      duration: 5000,
      position: "bottom-left",
    });
  };

  return <button onClick={showNotification}>Notify</button>;
}
```

### Complete Example

```tsx
import { ToastProvider, useAppToast, SelfButton } from "@leowjy/modal_js";
import "@leowjy/modal_js/dist/index.css";

function ToastDemo() {
  const toast = useAppToast();

  return (
    <div>
      <h2>Toast Notification Demo</h2>

      <SelfButton
        type="primary"
        onClick={() =>
          toast.success("Success! Your changes were saved.", {
            position: "top-right",
            duration: 3000,
          })
        }
      >
        Show Success Toast
      </SelfButton>

      <SelfButton
        type="danger"
        onClick={() =>
          toast.error("Error! Unable to process your request.", {
            position: "top-center",
            duration: 4000,
          })
        }
      >
        Show Error Toast
      </SelfButton>

      <SelfButton
        type="secondary"
        onClick={() =>
          toast.custom(
            <div style={{ display: "flex", alignItems: "center", gap: "10px" }}>
              <span>🎉</span>
              <div>
                <strong>Congratulations!</strong>
                <p>You've unlocked a new achievement.</p>
              </div>
            </div>,
            {
              className: "achievement-toast",
              style: { backgroundColor: "#6366f1", color: "white" },
              position: "bottom-center",
              duration: 5000,
            },
          )
        }
      >
        Show Custom Toast
      </SelfButton>
    </div>
  );
}

function App() {
  return (
    <ToastProvider>
      <ToastDemo />
    </ToastProvider>
  );
}

export default App;
```

## TypeScript Support

This package includes TypeScript definitions. Import types as needed:

## Styling

The components come with default styling. Please import CSS when you use the components or you can create your own style.

```tsx
import "@leowjy/modal_js/dist/index.css";
import "@leowjy/modal_js/dist/"
```

## License

MIT

## Author

[@leowjy](https://github.com/LeowJianYang)
[Github](https://github.com/LeowJianYang/Modal_js)

## Changelog

See [CHANGELOG.md](CHANGELOG.md) for a complete version history.

## License/Copyright

This project is licensed under the **MIT License** - see the [LICENSE.md](LICENSE.md) file for details.

## Acknowledgments

- [React](https://reactjs.org/)
- [Lucide Icons](https://lucide.dev/)