Compose accessible, unstyled application panels from directly styleable React components.
npm install @lucid-softworks/dialog-manager @lucid-softworks/panelimport { useState, type ReactElement } from "react";
import {
DialogManagerProvider,
useDialog,
useManager,
} from "@lucid-softworks/dialog-manager";
import { Panel } from "@lucid-softworks/panel";
interface Confirmation {
readonly confirmed: true;
}
function ConfirmationPanel(): ReactElement {
const dialog = useDialog<Confirmation>();
return (
<Panel.Root className="panel">
<Panel.Header className="panel-header">
<Panel.Title className="panel-title">Delete account?</Panel.Title>
<Panel.Actions className="panel-actions">
<button aria-label="Close" onClick={dialog.close} type="button">
×
</button>
</Panel.Actions>
</Panel.Header>
<Panel.Content className="panel-content">
<p>This action cannot be undone.</p>
</Panel.Content>
<Panel.Buttons className="panel-buttons">
<button onClick={dialog.close} type="button">
Cancel
</button>
<button
onClick={() => {
dialog.success({ confirmed: true });
}}
type="button"
>
Confirm
</button>
</Panel.Buttons>
</Panel.Root>
);
}
function AccountPage(): ReactElement {
const manager = useManager();
const [message, setMessage] = useState("No action taken.");
function openConfirmation(): void {
manager.open<Confirmation>({
id: "delete-account",
ariaLabel: "Delete account",
content: <ConfirmationPanel />,
onClose() {
setMessage("Deletion cancelled.");
},
onSuccess() {
setMessage("Account deleted.");
},
});
}
return (
<main>
<button onClick={openConfirmation} type="button">
Delete account
</button>
<p>{message}</p>
</main>
);
}
export function App(): ReactElement {
return (
<DialogManagerProvider>
<AccountPage />
</DialogManagerProvider>
);
}Panel.Root, Panel.Header, Panel.Title, Panel.Actions,
Panel.Content, and Panel.Buttons each render one semantic HTML element and
accept its standard React props. This lets consumers apply plain CSS, CSS
modules, Tailwind classes, inline styles, or StyleX props directly.
Panel.Header, Panel.Title, and Panel.Content are required.
Panel.Actions and Panel.Buttons are optional. Invalid nesting, missing
required parts, and duplicate parts are reported with clear errors.
Panel.Title renders an <h2>. The panel has no dialog-specific behaviour;
dialog naming and lifecycle remain the responsibility of the dialog manager.