### Install hiraku Package
Source: https://github.com/hirotoshioi/hiraku/blob/main/docs/guide/getting-started.md
Installs the hiraku library using various package managers like npm, pnpm, bun, and yarn. Ensure you have Node.js and a package manager installed.
```bash
npm install @hirotoshioi/hiraku
```
```bash
pnpm add @hirotoshioi/hiraku
```
```bash
bun add @hirotoshioi/hiraku
```
```bash
yarn add @hirotoshioi/hiraku
```
--------------------------------
### Install Radix UI Peer Dependencies
Source: https://github.com/hirotoshioi/hiraku/blob/main/docs/guide/getting-started.md
Installs the required Radix UI dialog primitives, @radix-ui/react-dialog and @radix-ui/react-alert-dialog, using npm, pnpm, bun, or yarn. These are necessary for hiraku's functionality.
```bash
npm install @radix-ui/react-dialog @radix-ui/react-alert-dialog
```
```bash
pnpm add @radix-ui/react-dialog @radix-ui/react-alert-dialog
```
```bash
bun add @radix-ui/react-dialog @radix-ui/react-alert-dialog
```
```bash
yarn add @radix-ui/react-dialog @radix-ui/react-alert-dialog
```
--------------------------------
### Install hiraku and Radix UI Dependencies
Source: https://github.com/hirotoshioi/hiraku/blob/main/README.md
Installs the hiraku package and the required Radix UI peer dependencies for dialogs and alerts.
```bash
npm install @hirotoshioi/hiraku
npm install @radix-ui/react-dialog @radix-ui/react-alert-dialog
```
--------------------------------
### Full Dialog Example with Type Inference
Source: https://github.com/hirotoshioi/hiraku/blob/main/docs/guide/api/create-dialog.md
A complete example demonstrating the creation, opening, and closing of a dialog component. It highlights automatic prop type inference for safety.
```tsx
import { createDialog } from "@hirotoshioi/hiraku";
import { DialogContent, DialogHeader, DialogTitle } from "@/components/ui/dialog";
interface Props {
name: string;
}
function GreetingDialog({ name }: Props) {
return (
Hello, {name}!
);
}
export const greetingDialog = createDialog(GreetingDialog);
// Usage
await greetingDialog.open({ name: "World" });
// Type Inference examples:
// ✅ Type-safe
greetingDialog.open({ name: "World" });
// ❌ Type error: missing 'name'
greetingDialog.open({});
// ❌ Type error: unknown prop
greetingDialog.open({ name: "World", foo: "bar" });
```
--------------------------------
### Alert Dialog Example with UI Components (TypeScript)
Source: https://github.com/hirotoshioi/hiraku/blob/main/docs/guide/api/create-alert-dialog.md
Provides a full example of creating and using an alert dialog for a confirmation action, such as deleting an item. It integrates with UI components for the dialog's structure and includes logic for opening, closing, and handling the result.
```typescript
import { createAlertDialog } from "@hirotoshioi/hiraku";
import {
AlertDialogContent,
AlertDialogHeader,
AlertDialogTitle,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogCancel,
AlertDialogAction,
} from "@/components/ui/alert-dialog";
interface DeleteConfirmProps {
itemName: string;
}
function DeleteConfirmDialog({ itemName }: DeleteConfirmProps) {
return (
Delete {itemName}?
This action cannot be undone. This will permanently delete the item.
deleteConfirm.close({ role: "cancel" })}
>
Cancel
deleteConfirm.close({ role: "confirm" })}
>
Delete
);
}
export const deleteConfirm = createAlertDialog(DeleteConfirmDialog);
// Usage
await deleteConfirm.open({ itemName: "Project Alpha" });
const result = await deleteConfirm.onDidClose();
if (result.role === "confirm") {
await deleteProject();
}
```
--------------------------------
### Example: Form with Confirmation using useModal (React/TypeScript)
Source: https://github.com/hirotoshioi/hiraku/blob/main/docs/guide/api/use-modal.md
A comprehensive example demonstrating a common use case: managing a form within a modal and handling confirmation actions. It shows how to open a modal, wait for its closure, and process the result.
```tsx
function EditProfileButton({ userId }: { userId: string }) {
const editModal = useModal(editProfileDialog);
const handleEdit = async () => {
await editModal.open({ userId });
const result = await editProfileDialog.onDidClose();
if (result.role === "confirm" && result.data) {
await updateProfile(userId, result.data);
toast.success("Profile updated!");
}
};
return (
);
}
```
--------------------------------
### Setup ModalProvider in React App
Source: https://github.com/hirotoshioi/hiraku/blob/main/docs/guide/api/modal-provider.md
Demonstrates how to integrate the ModalProvider component into the root of a React application. It requires importing ModalProvider and placing it within the component tree to enable modal functionality.
```tsx
import { ModalProvider } from "@hirotoshioi/hiraku";
function App() {
return (
<>
>
);
}
```
--------------------------------
### Full Example: Filter Sheet Modal (TypeScript)
Source: https://github.com/hirotoshioi/hiraku/blob/main/docs/guide/api/create-sheet.md
A comprehensive example demonstrating the creation and usage of a filter sheet modal. It includes defining the sheet component, specifying its return type, opening it with props, awaiting its closure, and processing the returned data.
```typescript
import { createSheet } from "@hirotoshioi/hiraku";
import {
SheetContent,
SheetHeader,
SheetTitle,
} from "@/components/ui/sheet";
interface FilterProps {
categories: string[];
}
function FilterSheet({ categories }: FilterProps) {
const [selected, setSelected] = useState([]);
return (
Filter
{categories.map((cat) => (
))}
);
}
export const filterSheet = createSheet(FilterSheet).returns();
// Usage
await filterSheet.open({ categories: ["Electronics", "Books", "Clothing"] });
const result = await filterSheet.onDidClose();
if (result.data) {
applyFilters(result.data);
}
```
--------------------------------
### Open and Handle Modal Result
Source: https://github.com/hirotoshioi/hiraku/blob/main/docs/guide/getting-started.md
Demonstrates how to open the previously created confirmDialog and await its result. It checks the role and data from the closed modal to determine user action.
```tsx
import { confirmDialog } from "./modals/confirm-dialog";
// Open the modal
await confirmDialog.open({
title: "Delete Item",
message: "Are you sure you want to delete this item?",
});
// Wait for the result
const result = await confirmDialog.onDidClose();
if (result.role === "confirm" && result.data) {
// User confirmed
deleteItem();
}
```
--------------------------------
### Boolean Confirmation Dialog Example in hiraku
Source: https://github.com/hirotoshioi/hiraku/blob/main/docs/guide/return-values.md
Demonstrates how to create a dialog that returns a boolean value for confirmation. It shows the creation of `confirmDialog` returning a boolean and how to handle the result to check if the user confirmed.
```tsx
export const confirmDialog = createDialog(ConfirmDialog).returns();
// Usage
const { data, role } = await confirmDialog.onDidClose();
if (role === "confirm" && data === true) {
// Confirmed
}
```
--------------------------------
### Setup ModalProvider with Next.js App Router
Source: https://github.com/hirotoshioi/hiraku/blob/main/docs/guide/api/modal-provider.md
Illustrates the integration of ModalProvider within a Next.js application utilizing the App Router. The provider is placed within the root layout file (`app/layout.tsx`) to ensure it's available across the entire application.
```tsx
// app/layout.tsx
import { ModalProvider } from "@hirotoshioi/hiraku";
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
{children}
);
}
```
--------------------------------
### Selection Return Type Example in hiraku
Source: https://github.com/hirotoshioi/hiraku/blob/main/docs/guide/return-values.md
Provides an example of a dialog that returns a selected string value, such as a color. It demonstrates creating a `colorPicker` dialog that returns a string and how to use the selected color.
```tsx
export const colorPicker = createDialog(ColorPickerDialog).returns();
// Usage
const { data: selectedColor } = await colorPicker.onDidClose();
if (selectedColor) {
applyColor(selectedColor);
}
```
--------------------------------
### Add ModalProvider to Application
Source: https://github.com/hirotoshioi/hiraku/blob/main/docs/guide/getting-started.md
Wraps your application with the ModalProvider component from hiraku. This component is essential for managing modal states globally within your React application.
```tsx
// app.tsx
import { ModalProvider } from "@hirotoshioi/hiraku";
function App() {
return (
<>
>
);
}
```
--------------------------------
### Create a Confirm Dialog Modal
Source: https://github.com/hirotoshioi/hiraku/blob/main/docs/guide/getting-started.md
Defines a ConfirmDialog component and its controller using hiraku's createDialog. This modal accepts title and message props and returns a boolean indicating confirmation.
```tsx
// modals/confirm-dialog.tsx
import { createDialog } from "@hirotoshioi/hiraku";
import {
DialogContent,
DialogHeader,
DialogTitle,
DialogFooter,
} from "@/components/ui/dialog";
import { Button } from "@/components/ui/button";
interface ConfirmDialogProps {
title: string;
message: string;
}
function ConfirmDialog({ title, message }: ConfirmDialogProps) {
return (
{title}
{message}
);
}
export const confirmDialog = createDialog(ConfirmDialog).returns();
```
--------------------------------
### Basic Usage of createSheet (TypeScript)
Source: https://github.com/hirotoshioi/hiraku/blob/main/docs/guide/api/create-sheet.md
Demonstrates the basic import and usage of the createSheet function to instantiate a sheet controller with a specific component. No return type is specified in this basic example.
```typescript
import { createSheet } from "@hirotoshioi/hiraku";
const mySheet = createSheet(MySheetComponent);
```
--------------------------------
### Handling Modal Results with useModal
Source: https://github.com/hirotoshioi/hiraku/blob/main/docs/guide/using-hooks.md
Shows how to handle the result of a modal interaction after it has been closed. This example demonstrates opening a modal, awaiting its closure, and then acting based on the `role` property of the result, such as confirming a deletion.
```tsx
function DeleteButton({ itemId }: { itemId: string }) {
const confirmModal = useModal(confirmDialog);
const handleDelete = async () => {
await confirmModal.open({
title: "Delete Item",
message: "Are you sure?",
});
const result = await confirmDialog.onDidClose();
if (result.role === "confirm") {
await deleteItem(itemId);
}
};
return (
);
}
```
--------------------------------
### Simplified Modal Opening (TypeScript)
Source: https://github.com/hirotoshioi/hiraku/blob/main/README.md
Illustrates hiraku's approach to opening modals without managing state in the parent component. This example shows a `Parent` component that can open a dialog (imported as `myDialog`) by simply calling `myDialog.open()`. This decouples the modal logic from the component hierarchy, unlike traditional methods that require passing state and handlers via props.
```tsx
import { myDialog } from "./modals/my-dialog";
function Parent() {
// const [isOpen, setIsOpen] = useState(false); <-- No need to manage state!
return (
<>
>
);
}
```
--------------------------------
### Form Data Return Type Example in hiraku
Source: https://github.com/hirotoshioi/hiraku/blob/main/docs/guide/return-values.md
Shows how to create a dialog that returns structured form data, specifically a `ContactForm` object. It illustrates defining the form interface and using `.returns()` to type the dialog's return value.
```tsx
interface ContactForm {
name: string;
email: string;
message: string;
}
export const contactDialog = createDialog(ContactDialog).returns();
// Usage
const { data } = await contactDialog.onDidClose();
if (data) {
await sendMessage(data);
}
```
--------------------------------
### Create AlertDialog Controller with createAlertDialog() in TypeScript
Source: https://context7.com/hirotoshioi/hiraku/llms.txt
The `createAlertDialog()` function is used to create modal controllers for alert dialogs that have blocking behavior. These dialogs require explicit user interaction to be dismissed, preventing closure via overlay clicks or the escape key. The example shows how to define and use a sample alert modal for confirmation before an action.
```tsx
import { createAlertDialog } from '@hirotoshioi/hiraku';
import {
AlertDialogContent,
AlertDialogHeader,
AlertDialogTitle,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogCancel,
AlertDialogAction,
} from '@/components/ui/alert-dialog';
export interface SampleAlertProps {
title: string;
message: string;
}
interface SampleAlertResult {
confirmed: boolean;
}
export const sampleAlert = createAlertDialog(SampleAlert).returns();
export function SampleAlert(props: SampleAlertProps) {
return (
{props.title}{props.message} sampleAlert.close({ role: "cancel" })}>
Cancel
sampleAlert.close({
data: { confirmed: true },
role: "confirm",
})
}
>
Continue
);
}
// Usage: Chain multiple modals
async function deleteWithConfirmation(itemId: string) {
await sampleAlert.open({
title: "Are you absolutely sure?",
message: "This action cannot be undone. This will permanently delete your data."
});
const result = await sampleAlert.onDidClose();
if (result.role === "confirm" && result.data?.confirmed) {
// Proceed with deletion
await deleteItem(itemId);
// Show success alert
await successAlert.open({ message: "Item deleted successfully" });
await successAlert.onDidClose();
}
}
```
--------------------------------
### Update React Usage Site for Hiraku Modal
Source: https://github.com/hirotoshioi/hiraku/blob/main/docs/guide/migration.md
Refactors how a modal is invoked and managed in a React application. It replaces the previous state-driven approach (using `useState` and `isOpen`/`onClose` props) with hiraku's controller pattern. The `confirmDialog.open` method is used to display the modal, and `confirmDialog.onDidClose` provides an asynchronous way to handle the modal's closing and retrieve its result.
```tsx
import { useState } from "react";
import { confirmDialog } from "./modals/confirm-dialog"; // Assuming the controller is exported from here
// Before Migration
function App_Before() {
const [isOpen, setIsOpen] = useState(false);
return (
<>
setIsOpen(false)}
onConfirm={() => {
console.log("Confirmed");
setIsOpen(false);
}}
message="Are you sure you want to delete?"
/>
>
);
}
// After Migration
function App_After() {
const handleClick = async () => {
// Use the controller to open the dialog and pass necessary props
await confirmDialog.open({ message: "Are you sure you want to delete?" });
// Wait for the dialog to close and get the result
const result = await confirmDialog.onDidClose();
if (result.role === "confirm") {
console.log("Confirmed");
}
};
return ;
}
```
--------------------------------
### Create Dialog Modal Controller with hiraku
Source: https://context7.com/hirotoshioi/hiraku/llms.txt
Demonstrates how to create a modal controller using `createDialog` for Radix UI Dialog components. It includes defining prop and return types, initializing the controller, rendering the modal content with form handling, and opening/closing the modal with data exchange. The `ModalProvider` must be set up in the application root.
```typescript
import { createDialog, ModalProvider } from '@hirotoshioi/hiraku';
import { DialogContent, DialogHeader, DialogTitle, DialogFooter } from '@/components/ui/dialog';
import { Button, Input } from '@/components/ui/button';
// Define prop and result types
interface EditProfileDialogProps {
initialName?: string;
initialUsername?: string;
}
interface ProfileData {
name: string;
username: string;
}
// Create the modal controller with return type
export const editProfileDialog = createDialog(EditProfileDialog).returns();
function EditProfileDialog({ initialName = "Pedro Duarte", initialUsername = "@peduarte" }: EditProfileDialogProps) {
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
const formData = new FormData(e.currentTarget);
const data = {
name: formData.get("name") as string,
username: formData.get("username") as string,
};
await editProfileDialog.close({ data, role: "confirm" });
};
return (
);
}
// Usage: Open from anywhere (even outside React)
async function updateProfile() {
await editProfileDialog.open({ initialName: "Jane Doe", initialUsername: "@jane" });
const result = await editProfileDialog.onDidClose();
if (result.role === "confirm" && result.data) {
console.log("Profile updated:", result.data.name, result.data.username);
} else {
console.log("Update cancelled");
}
}
// Setup in App root
function App() {
return (
<>
>
);
}
```
--------------------------------
### Get Topmost Modal Instance with Modal Controller
Source: https://github.com/hirotoshioi/hiraku/blob/main/docs/guide/modal-controller.md
This code demonstrates how to get the most recently opened modal instance using the `getTop()` method. If a modal is open, its ID is logged to the console.
```tsx
const topModal = modalController.getTop();
if (topModal) {
console.log("Top modal ID:", topModal.id);
}
```
--------------------------------
### Utilizing Reactive State with useModal
Source: https://github.com/hirotoshioi/hiraku/blob/main/docs/guide/using-hooks.md
Illustrates how to leverage the reactive `isOpen` state provided by the useModal hook to conditionally render UI elements or apply styles based on the modal's current visibility.
```tsx
function StatusIndicator() {
const { isOpen } = useModal(confirmDialog);
return (
{isOpen && }
);
}
```
--------------------------------
### Basic useModal Hook Usage in React
Source: https://github.com/hirotoshioi/hiraku/blob/main/docs/guide/using-hooks.md
Demonstrates the fundamental usage of the useModal hook to control a confirmation dialog within a React component. It shows how to initialize the hook with a modal controller, display the modal's open state, and trigger the modal opening with specific props.
```tsx
import { useModal } from "@hirotoshioi/hiraku";
import { confirmDialog } from "@/modals/confirm-dialog";
function MyComponent() {
const modal = useModal(confirmDialog);
return (
Modal is {modal.isOpen ? "open" : "closed"}
);
}
```
--------------------------------
### Get Count of Open Modals with modalController
Source: https://github.com/hirotoshioi/hiraku/blob/main/docs/guide/api/modal-controller.md
Returns the number of modals that are currently open. This can be used for displaying counts or for debugging purposes.
```tsx
const count = modalController.getCount();
console.log(`${count} modals open`);
```
--------------------------------
### Advanced Usage - Chaining Modals and Error Handling
Source: https://context7.com/hirotoshioi/hiraku/llms.txt
Demonstrates advanced patterns including sequential modal flows, nested modals, error handling, and integration with async operations using Hiraku.
```APIDOC
## Advanced Usage - Chaining Modals and Error Handling
### Description
Demonstrates advanced patterns including sequential modal flows, nested modals, error handling, and integration with async operations.
### Method
N/A (Usage Patterns)
### Endpoint
N/A
### Parameters
N/A
### Request Example
N/A
### Response
#### Success Response (N/A)
N/A
#### Response Example
N/A
## Usage Patterns
### Pattern 1: Sequential modal flow
```typescript
const selectFileDialog = createDialog(SelectFileDialog).returns<{ fileId: string }>();
const confirmDeleteDialog = createAlertDialog(ConfirmDelete).returns<{ confirmed: boolean }>();
const errorDialog = createAlertDialog(ErrorAlert);
const successDialog = createAlertDialog(SuccessAlert);
async function deleteFileWorkflow() {
try {
// Step 1: Select file
await selectFileDialog.open();
const fileResult = await selectFileDialog.onDidClose();
if (fileResult.role !== "confirm" || !fileResult.data) {
return; // User cancelled
}
// Step 2: Confirm deletion
await confirmDeleteDialog.open({ message: `Delete ${fileResult.data.fileId}?` });
const confirmResult = await confirmDeleteDialog.onDidClose();
if (confirmResult.role !== "confirm" || !confirmResult.data?.confirmed) {
return; // User cancelled
}
// Step 3: Perform deletion
await deleteFile(fileResult.data.fileId);
// Step 4: Show success
await successDialog.open({ message: "File deleted successfully" });
await successDialog.onDidClose();
} catch (error) {
// Show error modal
await errorDialog.open({
title: "Error",
message: error.message
});
await errorDialog.onDidClose();
}
}
```
### Pattern 2: Modal within modal (nested)
```typescript
// Assuming parentDialog is created elsewhere, e.g., const parentDialog = createDialog(ParentDialog);
function ParentDialog() {
const handleOpenNested = async () => {
await confirmDeleteDialog.open({ message: "Delete item?" });
const result = await confirmDeleteDialog.onDidClose();
if (result.data?.confirmed) {
// Close parent dialog with result
await parentDialog.close({ data: { deleted: true }, role: "confirm" });
}
};
return (
);
}
```
### Pattern 3: Conditional modal chains
```typescript
// Assuming approvalDialog and actionDialog are created elsewhere
async function conditionalFlow(requiresApproval: boolean) {
if (requiresApproval) {
await approvalDialog.open();
const approval = await approvalDialog.onDidClose();
if (approval.role !== "confirm") {
return { success: false, reason: "approval_denied" };
}
}
// Proceed with main action
await actionDialog.open();
const result = await actionDialog.onDidClose();
return { success: result.role === "confirm", data: result.data };
}
```
### Pattern 4: Timeout and cleanup
```typescript
// Assuming confirmDialog is created elsewhere
async function modalWithTimeout() {
const timeoutId = setTimeout(() => {
if (confirmDialog.isOpen()) {
confirmDialog.close({ role: "timeout" });
}
}, 30000); // 30 second timeout
await confirmDialog.open({ title: "Quick action required" });
const result = await confirmDialog.onDidClose();
clearTimeout(timeoutId);
if (result.role === "timeout") {
console.log("User took too long to respond");
}
}
```
```
--------------------------------
### Create a simple Dialog modal without props in React
Source: https://github.com/hirotoshioi/hiraku/blob/main/docs/guide/creating-modals.md
Demonstrates creating a Dialog modal with Hiraku's `createDialog` when no initial props are needed. This simple modal displays a greeting and can be opened without any arguments, showcasing a simplified usage pattern.
```tsx
function SimpleDialog() {
return (
Hello!
);
}
export const simpleDialog = createDialog(SimpleDialog);
// Open without arguments
await simpleDialog.open();
```
--------------------------------
### Get Count of Open Modals with Modal Controller
Source: https://github.com/hirotoshioi/hiraku/blob/main/docs/guide/modal-controller.md
This snippet illustrates how to retrieve the number of currently open modals using the `getCount()` method. The count is then logged to the console.
```tsx
const count = modalController.getCount();
console.log(`${count} modals are open`);
```
--------------------------------
### Opening a Modal with useModal.open() (React/TypeScript)
Source: https://github.com/hirotoshioi/hiraku/blob/main/docs/guide/api/use-modal.md
Shows how to programmatically open a modal using the `open` function provided by the useModal hook. It demonstrates passing props to the modal.
```tsx
const { open } = useModal(myDialog);
await open({ title: "Hello" });
```
--------------------------------
### Close Modals from Inside Modal (React)
Source: https://github.com/hirotoshioi/hiraku/blob/main/docs/guide/opening-closing.md
Provides examples of how to close a modal from within its own component using the `close` method, optionally passing data or a specific role.
```tsx
function MyDialog() {
return (
);
}
```
--------------------------------
### Get Topmost Modal Instance with modalController
Source: https://github.com/hirotoshioi/hiraku/blob/main/docs/guide/api/modal-controller.md
Retrieves the most recently opened (topmost) modal instance. If no modals are open, it returns undefined. This can be useful for interacting with the currently active modal.
```tsx
const top = modalController.getTop();
if (top) {
console.log("Top modal:", top.id);
}
```
--------------------------------
### Instantiate Alert Dialog with Return Type (TypeScript)
Source: https://github.com/hirotoshioi/hiraku/blob/main/docs/guide/api/create-alert-dialog.md
Demonstrates how to instantiate an alert dialog controller and specify a return type for the dialog's result. This allows for type-safe handling of data returned when the dialog is closed.
```typescript
const myAlertDialog = createAlertDialog(MyAlertDialogComponent).returns();
```
--------------------------------
### Create and use an AlertDialog modal in React
Source: https://github.com/hirotoshioi/hiraku/blob/main/docs/guide/creating-modals.md
Shows how to implement an AlertDialog using Hiraku's `createAlertDialog`. This modal is intended for critical confirmations and cannot be dismissed by clicking outside. It accepts an item name prop for personalization and allows the user to confirm or cancel the action, returning a role.
```tsx
import { createAlertDialog } from "@hirotoshioi/hiraku";
import {
AlertDialogContent,
AlertDialogHeader,
AlertDialogTitle,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogCancel,
AlertDialogAction,
} from "@/components/ui/alert-dialog";
interface DeleteConfirmProps {
itemName: string;
}
function DeleteConfirm({ itemName }: DeleteConfirmProps) {
return (
Delete {itemName}?
This action cannot be undone.
deleteConfirm.close({ role: "cancel" })}>
Cancel
deleteConfirm.close({ role: "confirm" })}>
Delete
);
}
export const deleteConfirm = createAlertDialog(DeleteConfirm);
```
--------------------------------
### Open Modals with Props (React)
Source: https://github.com/hirotoshioi/hiraku/blob/main/docs/guide/opening-closing.md
Demonstrates the basic usage of opening a confirmation dialog with specific props like title and message. This function is asynchronous and requires an `await` call.
```tsx
import { confirmDialog } from "@/modals/confirm-dialog";
// Open with props
await confirmDialog.open({
title: "Confirm Action",
message: "Are you sure?",
});
```
--------------------------------
### Multiple Values Return Type Example in hiraku
Source: https://github.com/hirotoshioi/hiraku/blob/main/docs/guide/return-values.md
Illustrates how to define a complex return type for a dialog or sheet, such as `FilterResult`, which includes multiple pieces of data like categories, price range, and sorting preferences.
```tsx
interface FilterResult {
categories: string[];
priceRange: [number, number];
sortBy: "price" | "date" | "name";
}
export const filterSheet = createSheet(FilterSheet).returns();
```
--------------------------------
### Modal Controller API: open(), close(), onDidClose(), isOpen() (React)
Source: https://context7.com/hirotoshioi/hiraku/llms.txt
Controllers created with `createDialog()`, `createSheet()`, or `createAlertDialog()` expose core methods for modal lifecycle management. These include opening modals with data, programmatically closing them, awaiting their closure, and checking their open state. This API allows for both synchronous and asynchronous interaction with modals.
```tsx
import { createDialog } from '@hirotoshioi/hiraku';
interface ConfirmDialogProps {
title: string;
message: string;
}
interface ConfirmDialogResult {
confirmed: boolean;
}
const confirmDialog = createDialog(ConfirmDialog).returns();
// Method 1: Await both open and close
async function askUserApproval() {
await confirmDialog.open({
title: "Confirm Action",
message: "Do you want to proceed?"
});
const result = await confirmDialog.onDidClose();
if (result.role === "confirm" && result.data?.confirmed) {
console.log("User confirmed");
}
}
// Method 2: Fire and forget open, await result later
function showConfirmationNonBlocking() {
confirmDialog.open({
title: "Background Task",
message: "A task is running in the background"
});
// Continue with other work...
// Check result later
confirmDialog.onDidClose().then((result) => {
console.log("User responded:", result.role);
});
}
// Method 3: Check state before opening
async function openIfNotOpen() {
if (!confirmDialog.isOpen()) {
await confirmDialog.open({
title: "New Dialog",
message: "This will only open if not already open"
});
}
}
// Method 4: Programmatic close from outside
async function forceCloseDialog() {
const closed = await confirmDialog.close({
data: { confirmed: false },
role: "dismiss"
});
if (closed) {
console.log("Dialog was closed programmatically");
}
}
```
--------------------------------
### modalController.isOpen()
Source: https://github.com/hirotoshioi/hiraku/blob/main/docs/guide/api/modal-controller.md
Checks if there is any modal currently open. Returns a boolean value indicating the open state.
```APIDOC
## modalController.isOpen()
### Description
Returns whether any modal is currently open.
### Method
`N/A` (This is a utility function call, not an HTTP request)
### Endpoint
`N/A`
### Parameters
None
### Request Example
```tsx
if (modalController.isOpen()) {
console.log("A modal is open");
}
```
### Response
#### Success Response
- **boolean**: `true` if a modal is open, `false` otherwise.
```
--------------------------------
### Import Modal Controller from Hiraku
Source: https://github.com/hirotoshioi/hiraku/blob/main/docs/guide/modal-controller.md
This snippet shows how to import the modalController utility from the '@hirotoshioi/hiraku' package. This import makes all modal management functions available for use in your application.
```tsx
import { modalController } from "@hirotoshioi/hiraku";
```
--------------------------------
### Close All Modals with Modal Controller
Source: https://github.com/hirotoshioi/hiraku/blob/main/docs/guide/modal-controller.md
Demonstrates closing all currently open modals using the `closeAll()` method. This is useful for scenarios like navigation changes, logouts, or error recovery where all modals should be dismissed simultaneously. An example using `useEffect` for route changes is also provided.
```tsx
// Close all modals immediately
modalController.closeAll();
```
```tsx
// Example: Close modals on route change
useEffect(() => {
return () => {
modalController.closeAll();
};
}, [pathname]);
```
--------------------------------
### Global Modal Controller Functions (TypeScript)
Source: https://github.com/hirotoshioi/hiraku/blob/main/README.md
Provides utility functions to manage all open modals globally. This includes closing all modals, getting the count of open modals, checking if any modal is open, and retrieving the topmost modal. It relies on the `modalController` object from the `@hirotoshioi/hiraku` library.
```tsx
import { modalController } from "@hirotoshioi/hiraku";
modalController.closeAll() // Close all open modals
modalController.getCount() // Get count of open modals
modalController.isOpen() // Check if any modal is open
modalController.getTop() // Get the topmost modal
```
--------------------------------
### Creating a Shadcn/UI Integrated Sheet Component (TypeScript)
Source: https://github.com/hirotoshioi/hiraku/blob/main/README.md
Demonstrates how to create a modal sheet component using hiraku's `createSheet` function, which integrates seamlessly with shadcn/ui's `SheetContent`, `SheetHeader`, and `SheetTitle` components. This approach simplifies modal creation by managing the `Root` component internally. The `createSheet` function takes a React component as an argument and returns a sheet instance.
```tsx
import { SheetContent, SheetHeader, SheetTitle } from "@/components/ui/sheet";
import { createSheet } from "@hirotoshioi/hiraku";
function MySheet({ title }: { title: string }) {
return (
{title}
{/* ... */}
);
}
export const mySheet = createSheet(MySheet);
```
--------------------------------
### Create Sheet Modal Controller with createSheet() in TypeScript
Source: https://context7.com/hirotoshioi/hiraku/llms.txt
The `createSheet()` function generates a modal controller for sheet or drawer components. It functions similarly to `createDialog()` but specifically configures the component for sheet-style modals. This example demonstrates creating a sample sheet with confirmation logic and handling its closing event.
```tsx
import { createSheet } from '@hirotoshioi/hiraku';
import { SheetContent, SheetHeader, SheetTitle, SheetFooter } from '@/components/ui/sheet';
import { Button } from '@/components/ui/button';
export interface SampleSheetProps {
title: string;
description: string;
}
interface SampleSheetResult {
accepted: boolean;
}
export const sampleSheetModal = createSheet(SampleSheet).returns();
export function SampleSheet(props: SampleSheetProps) {
const [isLoading, setIsLoading] = useState(false);
const handleConfirm = async () => {
setIsLoading(true);
await new Promise((resolve) => setTimeout(resolve, 2000));
setIsLoading(false);
await sampleSheetModal.close({
data: { accepted: true },
role: "confirm",
});
};
return (
{props.title}
);
}
// Usage: Promise-based flow with loading states
async function showConfirmationSheet() {
await sampleSheetModal.open({
title: "Confirm Action",
description: "Are you sure you want to proceed?"
});
const result = await sampleSheetModal.onDidClose();
if (result.role === "confirm" && result.data?.accepted) {
console.log("User confirmed after loading");
} else {
console.log("User cancelled");
}
}
```
--------------------------------
### Migrate React Dialog Component to Hiraku
Source: https://github.com/hirotoshioi/hiraku/blob/main/docs/guide/migration.md
Converts a Radix UI Dialog component to a hiraku modal component. The key change involves removing the Dialog.Root wrapper and utilizing hiraku's createDialog function to manage the modal's lifecycle and return values. This simplifies the component's internal structure and its interaction with the rest of the application.
```tsx
import * as Dialog from "@radix-ui/react-dialog";
import { createDialog } from "@hirotoshioi/hiraku";
// Before Migration
function ConfirmDialog_Before({ isOpen, onClose, onConfirm, message }) {
return (
Confirm
{message}
);
}
// After Migration
function ConfirmDialog_After({ message }: { message: string }) {
return (
// Dialog.Root is not needed! hiraku wraps it automatically
Confirm
{message}
);
}
export const confirmDialog = createDialog(ConfirmDialog_After).returns();
```
--------------------------------
### useModal Hook Signature and Usage (TypeScript/React)
Source: https://github.com/hirotoshioi/hiraku/blob/main/docs/guide/api/use-modal.md
Demonstrates the signature of the useModal hook and its basic usage within a React component. It shows how to import and invoke the hook, and how to render a button that toggles the modal's open state.
```tsx
import { useModal } from "@hirotoshioi/hiraku";
import { confirmDialog } from "@/modals/confirm-dialog";
function MyComponent() {
const modal = useModal(confirmDialog);
return (
);
}
```
--------------------------------
### Global Modal Controller Utilities (JavaScript)
Source: https://context7.com/hirotoshioi/hiraku/llms.txt
The `modalController` object provides utility methods for managing modals globally. It's useful for controlling multiple modals, checking global state, and implementing escape handlers. It allows operations like closing all modals, getting the topmost modal, and checking the count of open modals.
```javascript
import { modalController } from '@hirotoshioi/hiraku';
// Close all open modals at once
async function handleEscapeKey(e: KeyboardEvent) {
if (e.key === 'Escape' && modalController.isOpen()) {
await modalController.closeAll();
}
}
// Get the topmost modal and interact with it
function handleGlobalAction() {
const topModal = modalController.getTop();
if (topModal) {
topModal.close({ role: "dismiss" });
}
}
// Check how many modals are currently open
function displayModalCount() {
const count = modalController.getCount();
console.log(`${count} modal(s) currently open`);
}
// Check if any modal is open
function preventNavigation(to: string) {
if (modalController.isOpen()) {
console.log("Please close all modals before navigating");
return false;
}
return true;
}
```
--------------------------------
### Create a Custom Dialog Modal with hiraku
Source: https://github.com/hirotoshioi/hiraku/blob/main/README.md
Shows how to define a custom React component for a dialog and create a modal controller using `createDialog` from hiraku. The `returns()` part specifies the expected return type when the modal is closed.
```tsx
import { DialogContent, DialogHeader, DialogTitle, DialogFooter } from "@/components/ui/dialog";
import { Button } from "@/components/ui/button";
import { createDialog } from "@hirotoshioi/hiraku";
interface ConfirmDialogProps {
title: string;
message: string;
}
// No need to wrap with Dialog.Root, hiraku will take care of it
function ConfirmDialog({ title, message }: ConfirmDialogProps) {
return (
{title}
{message}
);
}
// Create a modal controller
export const confirmDialog = createDialog(ConfirmDialog).returns();
```
--------------------------------
### Chaining and Nested Modals with @hirotoshioi/hiraku
Source: https://context7.com/hirotoshioi/hiraku/llms.txt
Demonstrates advanced patterns for modal interactions using the @hirotoshioi/hiraku library, including sequential modal flows, nested modals, conditional chains, and error handling with async operations. It showcases how to chain multiple dialogs and manage complex user interactions. Dependencies include the '@hirotoshioi/hiraku' library.
```tsx
import { createDialog, createAlertDialog } from '@hirotoshioi/hiraku';
// Define multiple related modals
const selectFileDialog = createDialog(SelectFileDialog).returns<{ fileId: string }>();
const confirmDeleteDialog = createAlertDialog(ConfirmDelete).returns<{ confirmed: boolean }>();
const errorDialog = createAlertDialog(ErrorAlert);
// Pattern 1: Sequential modal flow
async function deleteFileWorkflow() {
try {
// Step 1: Select file
await selectFileDialog.open();
const fileResult = await selectFileDialog.onDidClose();
if (fileResult.role !== "confirm" || !fileResult.data) {
return; // User cancelled
}
// Step 2: Confirm deletion
await confirmDeleteDialog.open({ message: `Delete ${fileResult.data.fileId}?` });
const confirmResult = await confirmDeleteDialog.onDidClose();
if (confirmResult.role !== "confirm" || !confirmResult.data?.confirmed) {
return; // User cancelled
}
// Step 3: Perform deletion
await deleteFile(fileResult.data.fileId);
// Step 4: Show success
await successDialog.open({ message: "File deleted successfully" });
await successDialog.onDidClose();
} catch (error) {
// Show error modal
await errorDialog.open({
title: "Error",
message: error.message
});
await errorDialog.onDidClose();
}
}
// Pattern 2: Modal within modal (nested)
function ParentDialog() {
const handleOpenNested = async () => {
await confirmDeleteDialog.open({ message: "Delete item?" });
const result = await confirmDeleteDialog.onDidClose();
if (result.data?.confirmed) {
// Close parent dialog with result
await parentDialog.close({ data: { deleted: true }, role: "confirm" });
}
};
return (
);
}
// Pattern 3: Conditional modal chains
async function conditionalFlow(requiresApproval: boolean) {
if (requiresApproval) {
await approvalDialog.open();
const approval = await approvalDialog.onDidClose();
if (approval.role !== "confirm") {
return { success: false, reason: "approval_denied" };
}
}
// Proceed with main action
await actionDialog.open();
const result = await actionDialog.onDidClose();
return { success: result.role === "confirm", data: result.data };
}
// Pattern 4: Timeout and cleanup
async function modalWithTimeout() {
const timeoutId = setTimeout(() => {
if (confirmDialog.isOpen()) {
confirmDialog.close({ role: "timeout" });
}
}, 30000); // 30 second timeout
await confirmDialog.open({ title: "Quick action required" });
const result = await confirmDialog.onDidClose();
clearTimeout(timeoutId);
if (result.role === "timeout") {
console.log("User took too long to respond");
}
}
```
--------------------------------
### Open Modals from Event Handlers (React)
Source: https://github.com/hirotoshioi/hiraku/blob/main/docs/guide/opening-closing.md
Shows how to trigger a modal opening from a React component's event handler, such as a button click. It also demonstrates how to await the closing of the modal and process its result.
```tsx
function DeleteButton({ itemId }: { itemId: string }) {
const handleClick = async () => {
await confirmDialog.open({
title: "Delete item",
message: "Delete this item?",
});
const result = await confirmDialog.onDidClose();
if (result.role === "confirm") {
await deleteItem(itemId);
}
};
return ;
}
```
--------------------------------
### Using isOpen State with useModal (React/TypeScript)
Source: https://github.com/hirotoshioi/hiraku/blob/main/docs/guide/api/use-modal.md
Illustrates how to utilize the `isOpen` state returned by useModal to conditionally apply styles or render content. This is useful for visual feedback when the modal is active.
```tsx
const { isOpen } = useModal(myDialog);
return (
);
```
--------------------------------
### Open Dialog with Props
Source: https://github.com/hirotoshioi/hiraku/blob/main/docs/guide/api/create-dialog.md
Asynchronously opens the modal associated with the controller, passing any necessary props to the dialog component. Resolves when the modal is presented.
```tsx
await myDialog.open({ title: "Hello" });
```