overlay-manager-rc
v0.8.2
Published
React overlay component manager
Downloads
608
Maintainers
Readme
Overlay-manager-rc
English | 한국어
Inspired by angular cdk overlay
React overlay component manager
Feature
- (alert-dialog, dialog, sheet...) open, close state no more management.
- You don't need to worry about declaring overlay component. It's okay to have multiple overlays.
- Delivering data to overlay component props.
- Detect when an overlay component is closed; the resulting data is received on close.
- Prevent closing with beforeClose logic. Asynchronous result handling with await.
- Simplified API with automatic ID management.
- No unnecessary renders when opening or closing overlay components.
- React 19 support
Install
npm
npm install overlay-manager-rc
yarn
yarn add overlay-manager-rc
pnpm
pnpm add overlay-manager-rc
Setting
ex) nextjs(app router) + shadcn-ui(radix-ui)
already install
- alert-dialog
Step1
make file overlay-manager-provider.tsx
;
'use client';
import type { ReactNode } from 'react';
import { OverlayContainer } from "overlay-manager-rc";
export function OverlayContainerNext({ children }: { children?: ReactNode }) {
return <OverlayContainer/>;
}
Step2
set provider in layout.tsx
component
export default function RootLayout({ children }: { children: ReactNode }) {
return (
<html lang="en" suppressHydrationWarning>
<body className={cn('min-h-screen font-sans antialiased dark')}>
{children}
<OverlayContainerNext />
</body>
</html>
);
}
Usage
Create overlay component
import type {OverlayContentProps} from 'overlay-manager-rc';
import {useBeforeClose} from 'overlay-manager-rc'; // Import useBeforeClose
export function TestContent({
open,
data,
close,
id // add id prop
}: OverlayContentProps<string>) {
// Example of using useBeforeClose hook
useBeforeClose(async () => {
const confirmed = window.confirm('Are you sure you want to close?');
return confirmed; // returns true to close, false to prevent closing
}, id); // pass id to useBeforeClose
return (
<AlertDialog
onOpenChange={(v) => {
!v && close();
}}
open={open}
>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>Alert title</AlertDialogTitle>
<AlertDialogDescription>Get Data: {data}</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel>Cancel</AlertDialogCancel>
<AlertDialogAction>Continue</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
);
}
Open overlay
'use client';
import { useOverlayManager } from 'overlay-manager-rc';
export function AlertSection() {
const { openOverlay } = useOverlayManager();
const handleOpenAlert = async () => {
const result = await openOverlay({
content: TestContent,
data: 'hello!!!!',
onClose: (result) => {
console.log('Dialog closed with result:', result);
},
onOpen: (id) => {
console.log('Overlay opened with id:', id);
},
});
console.log('Result from openOverlay:', result); // Same value as onClose result
};
return (
<section className="md:h-screen">
<div className="flex flex-col gap-10">
<Button onClick={handleOpenAlert}>
show alert
</Button>
</div>
</section>
);
}
Receive resulting data when closing
export function TestContent({data, close}: OverlayContentProps<string, boolean>) {
return (
<AlertDialog>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>Alert title</AlertDialogTitle>
<AlertDialogDescription>Get Data: {data}</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel onClick={() => close(false)}>Cancel</AlertDialogCancel>
<AlertDialogAction onClick={() => close(true)}>Continue</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
);
}
/* open handler */
const handleOpenAlert = () => {
openOverlay({
content: TestContent,
data: 'hello!!!!',
onClose: (result) => {
console.log('Dialog closed with result:', result);
}
});
};
API
useOverlayManager
returns
| name | description | parameter | | --- | --- | --- | | openOverlay | Opens an overlay component. Returns a Promise. | OverlayOptions | | closeAllOverlays | Closes all overlay components. | - | | closeOverlayById | Closes an overlay component by ID. | id: string |
OverlayOptions<TData, TResult>
| Prop | Type | Default | Required | | --- | --- | --- | --- | | id | string | - | No | | content | OverlayContent<TData, TResult> | - | Yes | | data | TData | - | No | | onClose | (result?: TResult) => void | Promise | - | No | | onOpen | (id: string) => void | Promise | - | No | | beforeClose | () => boolean | Promise | - | No |
OverlayContentProps<TData, TResult>
| Prop | Type | Default | Required | | --- | --- | --- | --- | | data | TData | - | Yes | | close | (result?: TResult) => void | - | Yes | | open | boolean | - | Yes | | id | string | - | Yes |
useBeforeClose
import { useBeforeClose } from 'overlay-manager-rc/useBeforeClose';
// ... inside your overlay component
useBeforeClose(async () => {
// Your logic to determine whether to prevent closing.
// For example, check if a form is dirty.
const canClose = window.confirm('Are you sure you want to close?');
return canClose; // Return true to allow closing, false to prevent it.
}, id); // Pass the overlay's ID