### 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 (
Edit profile
); } // 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" }); ```