@page "/components/overlay-service"

@using Lumeo.Services
@using Lumeo.Docs.Shared

<PageTitle>Overlay Service — Lumeo</PageTitle>

<PageHeader Title="Overlay Service" Description="A programmatic service for opening dialogs, sheets, drawers, and alert dialogs imperatively from code." />

<Stack Gap="8">

    <!-- Dialog demo -->
    <ComponentDemo Title="Dialog" Description="Open a dialog containing a dynamic component and await its result." Code="@_dialogCode">
        <Stack Gap="3">
            <Button OnClick="ShowDialog">Open Dialog</Button>
            @if (_dialogResult is not null)
            {
                <Alert>Result: @_dialogResult</Alert>
            }
        </Stack>
    </ComponentDemo>

    <Alert Variant="Alert.AlertVariant.Info" ShowIcon="true">
        <ChildContent>
            <strong>Authoring components for the service.</strong> When a component is opened via
            <code class="rounded bg-muted px-1.5 py-0.5 text-xs font-mono">OverlayService.Show*Async&lt;T&gt;</code>,
            the provider already wraps it in <code class="rounded bg-muted px-1.5 py-0.5 text-xs font-mono">&lt;Dialog&gt;&lt;DialogContent&gt;</code>
            (or the Sheet / Drawer equivalent). Your component renders as the children of that shell — put
            <code class="rounded bg-muted px-1.5 py-0.5 text-xs font-mono">&lt;DialogHeader&gt;</code>,
            <code class="rounded bg-muted px-1.5 py-0.5 text-xs font-mono">&lt;DialogFooter&gt;</code>
            (or the Sheet / Drawer equivalents) and your body content directly at the root.
            Inline-declarative usage (<code class="rounded bg-muted px-1.5 py-0.5 text-xs font-mono">&lt;Sheet&gt;&lt;SheetContent&gt;...&lt;/SheetContent&gt;&lt;/Sheet&gt;</code>)
            inside a service-opened component is detected and passes through — but the cleaner pattern is
            to skip the outer wrappers entirely.
        </ChildContent>
    </Alert>

    <!-- Sheet demo -->
    <ComponentDemo Title="Sheet" Description="Open a sheet panel from any side with a dynamic component." Code="@_sheetCode">
        <Stack Gap="3">
            <Flex Gap="2" Wrap="true">
                <Button Variant="Button.ButtonVariant.Outline" OnClick="() => ShowSheet(SheetSide.Right)">Right</Button>
                <Button Variant="Button.ButtonVariant.Outline" OnClick="() => ShowSheet(SheetSide.Left)">Left</Button>
                <Button Variant="Button.ButtonVariant.Outline" OnClick="() => ShowSheet(SheetSide.Bottom)">Bottom</Button>
            </Flex>
            @if (_sheetResult is not null)
            {
                <Alert>Result: @_sheetResult</Alert>
            }
        </Stack>
    </ComponentDemo>

    <!-- Drawer demo -->
    <ComponentDemo Title="Drawer" Description="Open a bottom drawer with a dynamic component." Code="@_drawerCode">
        <Stack Gap="3">
            <Button Variant="Button.ButtonVariant.Outline" OnClick="ShowDrawer">Open Drawer</Button>
            @if (_drawerResult is not null)
            {
                <Alert>Result: @_drawerResult</Alert>
            }
        </Stack>
    </ComponentDemo>

    <!-- Alert Dialog demo -->
    <ComponentDemo Title="Alert Dialog" Description="Show a confirmation dialog and await the user's choice." Code="@_alertCode">
        <Stack Gap="3">
            <Flex Gap="2" Wrap="true">
                <Button Variant="Button.ButtonVariant.Outline" OnClick="ShowConfirm">Confirm Action</Button>
                <Button Variant="Button.ButtonVariant.Destructive" OnClick="ShowDestructive">Delete Item</Button>
            </Flex>
            @if (_alertResult is not null)
            {
                <Alert Variant="@(_alertCancelled ? Alert.AlertVariant.Destructive : Alert.AlertVariant.Default)">@_alertResult</Alert>
            }
        </Stack>
    </ComponentDemo>

</Stack>

<!-- API Reference -->
<Stack Gap="6" Class="mt-12">
    <Heading Level="2">API Reference</Heading>

    <Stack Gap="8">

        <Stack>
            <Heading Level="3" Class="mb-3">OverlayService</Heading>
            <Stack Class="rounded-lg border border-border/40 overflow-x-auto">
                <table class="w-full min-w-[600px] text-sm">
                    <thead>
                        <tr class="border-b border-border/40 bg-muted/40">
                            <th class="text-left p-3 font-medium text-foreground">Method</th>
                            <th class="text-left p-3 font-medium text-foreground">Signature</th>
                            <th class="text-left p-3 font-medium text-foreground">Description</th>
                        </tr>
                    </thead>
                    <tbody class="divide-y divide-border/40">
                        <tr>
                            <td class="p-3 font-mono text-xs text-primary">ShowDialogAsync</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">ShowDialogAsync&lt;TComponent&gt;(title?, parameters?, options?)</td>
                            <td class="p-3 text-muted-foreground">Opens a Dialog containing the given component. Returns a Task&lt;OverlayResult&gt;.</td>
                        </tr>
                        <tr>
                            <td class="p-3 font-mono text-xs text-primary">ShowSheetAsync</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">ShowSheetAsync&lt;TComponent&gt;(title?, side, size, parameters?, options?)</td>
                            <td class="p-3 text-muted-foreground">Opens a Sheet panel. Side defaults to Right. Returns a Task&lt;OverlayResult&gt;.</td>
                        </tr>
                        <tr>
                            <td class="p-3 font-mono text-xs text-primary">ShowDrawerAsync</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">ShowDrawerAsync&lt;TComponent&gt;(title?, parameters?, options?)</td>
                            <td class="p-3 text-muted-foreground">Opens a Drawer from the bottom. Returns a Task&lt;OverlayResult&gt;.</td>
                        </tr>
                        <tr>
                            <td class="p-3 font-mono text-xs text-primary">ShowAlertDialogAsync</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">ShowAlertDialogAsync(alertOptions)</td>
                            <td class="p-3 text-muted-foreground">Shows a confirmation alert dialog. Returns a Task&lt;OverlayResult&gt;.</td>
                        </tr>
                        <tr>
                            <td class="p-3 font-mono text-xs text-primary">Close</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">Close(overlayId, result?)</td>
                            <td class="p-3 text-muted-foreground">Closes an overlay and resolves its task with the given result data.</td>
                        </tr>
                        <tr>
                            <td class="p-3 font-mono text-xs text-primary">Cancel</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">Cancel(overlayId)</td>
                            <td class="p-3 text-muted-foreground">Cancels an overlay, resolving its task with a cancelled result.</td>
                        </tr>
                    </tbody>
                </table>
            </Stack>
        </Stack>

        <Stack>
            <Heading Level="3" Class="mb-3">OverlayResult</Heading>
            <Stack Class="rounded-lg border border-border/40 overflow-x-auto">
                <table class="w-full min-w-[600px] text-sm">
                    <thead>
                        <tr class="border-b border-border/40 bg-muted/40">
                            <th class="text-left p-3 font-medium text-foreground">Member</th>
                            <th class="text-left p-3 font-medium text-foreground">Type</th>
                            <th class="text-left p-3 font-medium text-foreground">Description</th>
                        </tr>
                    </thead>
                    <tbody class="divide-y divide-border/40">
                        <tr>
                            <td class="p-3 font-mono text-xs text-primary">Cancelled</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">bool</td>
                            <td class="p-3 text-muted-foreground">True when the user dismissed the overlay without confirming.</td>
                        </tr>
                        <tr>
                            <td class="p-3 font-mono text-xs text-primary">Data</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">object?</td>
                            <td class="p-3 text-muted-foreground">The result value passed to Close().</td>
                        </tr>
                        <tr>
                            <td class="p-3 font-mono text-xs text-primary">GetData&lt;T&gt;()</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">T?</td>
                            <td class="p-3 text-muted-foreground">Casts and returns the result data as T.</td>
                        </tr>
                    </tbody>
                </table>
            </Stack>
        </Stack>

        <Stack>
            <Heading Level="3" Class="mb-3">OverlayReference</Heading>
            <Stack Class="rounded-lg border border-border/40 overflow-x-auto">
                <table class="w-full min-w-[600px] text-sm">
                    <thead>
                        <tr class="border-b border-border/40 bg-muted/40">
                            <th class="text-left p-3 font-medium text-foreground">Member</th>
                            <th class="text-left p-3 font-medium text-foreground">Type</th>
                            <th class="text-left p-3 font-medium text-foreground">Description</th>
                        </tr>
                    </thead>
                    <tbody class="divide-y divide-border/40">
                        <tr>
                            <td class="p-3 font-mono text-xs text-primary">Id</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">string</td>
                            <td class="p-3 text-muted-foreground">Unique identifier for this overlay instance.</td>
                        </tr>
                        <tr>
                            <td class="p-3 font-mono text-xs text-primary">Parameters</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">OverlayParameters?</td>
                            <td class="p-3 text-muted-foreground">The parameters passed when the overlay was opened.</td>
                        </tr>
                        <tr>
                            <td class="p-3 font-mono text-xs text-primary">Close(result?)</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">void</td>
                            <td class="p-3 text-muted-foreground">Closes the overlay and resolves with optional result data.</td>
                        </tr>
                        <tr>
                            <td class="p-3 font-mono text-xs text-primary">Cancel()</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">void</td>
                            <td class="p-3 text-muted-foreground">Cancels the overlay, setting Cancelled = true on the result.</td>
                        </tr>
                    </tbody>
                </table>
            </Stack>
        </Stack>

        <Stack>
            <Heading Level="3" Class="mb-3">OverlayParameters</Heading>
            <Stack Class="rounded-lg border border-border/40 overflow-x-auto">
                <table class="w-full min-w-[600px] text-sm">
                    <thead>
                        <tr class="border-b border-border/40 bg-muted/40">
                            <th class="text-left p-3 font-medium text-foreground">Method</th>
                            <th class="text-left p-3 font-medium text-foreground">Signature</th>
                            <th class="text-left p-3 font-medium text-foreground">Description</th>
                        </tr>
                    </thead>
                    <tbody class="divide-y divide-border/40">
                        <tr>
                            <td class="p-3 font-mono text-xs text-primary">Add</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">Add(name, value) → OverlayParameters</td>
                            <td class="p-3 text-muted-foreground">Adds a named parameter. Returns itself for chaining.</td>
                        </tr>
                        <tr>
                            <td class="p-3 font-mono text-xs text-primary">Get&lt;T&gt;</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">Get&lt;T&gt;(name) → T?</td>
                            <td class="p-3 text-muted-foreground">Retrieves a parameter by name cast to type T.</td>
                        </tr>
                        <tr>
                            <td class="p-3 font-mono text-xs text-primary">ToDictionary</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">ToDictionary() → Dictionary&lt;string, object&gt;</td>
                            <td class="p-3 text-muted-foreground">Returns all parameters as a dictionary for DynamicComponent use.</td>
                        </tr>
                    </tbody>
                </table>
            </Stack>
        </Stack>

        <Stack>
            <Heading Level="3" Class="mb-3">OverlayOptions</Heading>
            <Stack Class="rounded-lg border border-border/40 overflow-x-auto">
                <table class="w-full min-w-[600px] text-sm">
                    <thead>
                        <tr class="border-b border-border/40 bg-muted/40">
                            <th class="text-left p-3 font-medium text-foreground">Property</th>
                            <th class="text-left p-3 font-medium text-foreground">Type</th>
                            <th class="text-left p-3 font-medium text-foreground">Default</th>
                            <th class="text-left p-3 font-medium text-foreground">Description</th>
                        </tr>
                    </thead>
                    <tbody class="divide-y divide-border/40">
                        <tr>
                            <td class="p-3 font-mono text-xs text-primary">Class</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">string?</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">null</td>
                            <td class="p-3 text-muted-foreground">Additional CSS class for the overlay container.</td>
                        </tr>
                        <tr>
                            <td class="p-3 font-mono text-xs text-primary">PreventClose</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">bool</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">false</td>
                            <td class="p-3 text-muted-foreground">When true, the close button and backdrop click are disabled.</td>
                        </tr>
                        <tr>
                            <td class="p-3 font-mono text-xs text-primary">SheetSide</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">SheetSide</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">Right</td>
                            <td class="p-3 text-muted-foreground">Which side the sheet slides in from.</td>
                        </tr>
                        <tr>
                            <td class="p-3 font-mono text-xs text-primary">SheetSize</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">SheetSize</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">Default</td>
                            <td class="p-3 text-muted-foreground">Sheet dimension. On <code>Left</code>/<code>Right</code> controls width; on <code>Top</code>/<code>Bottom</code> controls height (2.1.1). <code>Full</code> on <code>Bottom</code> + <code>SwipeToClose=true</code> gives the mobile-fullscreen sheet pattern.</td>
                        </tr>
                        <tr>
                            <td class="p-3 font-mono text-xs text-primary">SwipeToClose</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">bool</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">false</td>
                            <td class="p-3 text-muted-foreground">Sheet-only (2.1.1). Pipes the SwipeToClose flag through to the rendered <code>SheetContent</code> so programmatically-opened sheets can be dismissed by swiping in the direction matching <code>SheetSide</code>. Default false to keep existing programmatic-open behaviour. Drawers already swipe-close by default.</td>
                        </tr>
                        <tr>
                            <td class="p-3 font-mono text-xs text-primary">MobileBreakpoint</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">int?</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">768</td>
                            <td class="p-3 text-muted-foreground">Sheet-only (2.1.3). Viewport width threshold (CSS px) below which the <code>Mobile*</code> overrides activate. Default 768 = Tailwind <code>md</code>. Set to <code>null</code> to disable responsive switching entirely.</td>
                        </tr>
                        <tr>
                            <td class="p-3 font-mono text-xs text-primary">MobileSheetSide</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">SheetSide?</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">null</td>
                            <td class="p-3 text-muted-foreground">Sheet-only (2.1.3). Side override used when the viewport is below <code>MobileBreakpoint</code>. Typical pattern: <code>SheetSide.Right</code> on desktop, <code>SheetSide.Bottom</code> on mobile. <code>null</code> keeps <code>SheetSide</code> at every size.</td>
                        </tr>
                        <tr>
                            <td class="p-3 font-mono text-xs text-primary">MobileSheetSize</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">SheetSize?</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">null</td>
                            <td class="p-3 text-muted-foreground">Sheet-only (2.1.3). Size override used below <code>MobileBreakpoint</code>. Pair with <code>MobileSheetSide=Bottom</code> + <code>MobileSheetSize=Full</code> for the mobile-fullscreen bottom-sheet pattern.</td>
                        </tr>
                        <tr>
                            <td class="p-3 font-mono text-xs text-primary">MobileSwipeToClose</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">bool?</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">null</td>
                            <td class="p-3 text-muted-foreground">Sheet-only (2.1.3). SwipeToClose override below <code>MobileBreakpoint</code>. Typical: <code>false</code> on desktop side panel, <code>true</code> on mobile bottom sheet so the pull-down dismiss is available.</td>
                        </tr>
                    </tbody>
                </table>
            </Stack>
        </Stack>

        <Stack>
            <Heading Id="responsive-sheets" Level="3" Class="mb-3">Responsive sheets (2.1.3)</Heading>
            <Lumeo.Text Size="sm" Color="muted" Class="mb-3">
                A single <code>ShowSheetAsync</code> call can switch between a side panel on desktop and a fullscreen bottom sheet on mobile, including SwipeToClose behaviour. <code>OverlayProvider</code> subscribes to <code>IResponsiveService.ViewportChanged</code> and re-renders the effective Side/Size/SwipeToClose when the viewport crosses <code>MobileBreakpoint</code> — works mid-flight (user rotates a tablet, sheet flips correctly).
            </Lumeo.Text>
            <pre class="rounded-md border border-border/40 bg-muted/30 p-3 text-xs overflow-x-auto"><code>// In any component:
@@inject OverlayService Overlay

private async Task ShowResponsive()
{
    await Overlay.ShowSheetAsync&lt;MyForm&gt;(
        title: "Edit user",
        side: SheetSide.Right,                      // desktop default
        size: SheetSize.Default,
        options: new OverlayOptions
        {
            // Below 768px, switch to a fullscreen bottom sheet with swipe-down dismiss
            MobileSheetSide    = SheetSide.Bottom,
            MobileSheetSize    = SheetSize.Full,
            MobileSwipeToClose = true,
            // MobileBreakpoint defaults to 768 (md) — set to null to disable
        });
}</code></pre>
            <Lumeo.Text Size="sm" Color="muted" Class="mt-3">
                If you need finer-grained mobile detection (e.g. to change the rendered content, not just overlay sizing), inject <code>IResponsiveService</code> directly. See the IResponsiveService API below.
            </Lumeo.Text>
        </Stack>

        <Stack>
            <Heading Id="responsive-service" Level="3" Class="mb-3">IResponsiveService (2.1.3)</Heading>
            <Lumeo.Text Size="sm" Color="muted" Class="mb-3">
                Reactive viewport/breakpoint service. One JS resize listener per circuit (debounced 100ms), Tailwind-v4-aligned <code>Breakpoint</code> enum, plus <code>IsMobile</code>/<code>IsTablet</code>/<code>IsDesktop</code> convenience flags and a <code>ViewportChanged</code> event for components that need to react to the live viewport.
            </Lumeo.Text>
            <Stack Class="rounded-lg border border-border/40 overflow-x-auto">
                <table class="w-full min-w-[600px] text-sm">
                    <thead>
                        <tr class="border-b border-border/40 bg-muted/40">
                            <th class="text-left p-3 font-medium text-foreground">Member</th>
                            <th class="text-left p-3 font-medium text-foreground">Type</th>
                            <th class="text-left p-3 font-medium text-foreground">Description</th>
                        </tr>
                    </thead>
                    <tbody class="divide-y divide-border/40">
                        <tr>
                            <td class="p-3 font-mono text-xs text-primary">Width</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">double</td>
                            <td class="p-3 text-muted-foreground">Current viewport width in CSS pixels (window.innerWidth). 0 until the first interop sync — call <code>EnsureInitialisedAsync</code> from <code>OnAfterRenderAsync(firstRender: true)</code> or subscribe to <code>ViewportChanged</code>.</td>
                        </tr>
                        <tr>
                            <td class="p-3 font-mono text-xs text-primary">Height</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">double</td>
                            <td class="p-3 text-muted-foreground">Current viewport height in CSS pixels.</td>
                        </tr>
                        <tr>
                            <td class="p-3 font-mono text-xs text-primary">Current</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">Breakpoint</td>
                            <td class="p-3 text-muted-foreground">Tailwind-aligned breakpoint. Values: <code>Xs</code> (&lt;640), <code>Sm</code> ([640,768)), <code>Md</code> ([768,1024)), <code>Lg</code> ([1024,1280)), <code>Xl</code> ([1280,1536)), <code>Xxl</code> (&gt;=1536).</td>
                        </tr>
                        <tr>
                            <td class="p-3 font-mono text-xs text-primary">IsMobile</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">bool</td>
                            <td class="p-3 text-muted-foreground">True when <code>Current</code> is <code>Xs</code> or <code>Sm</code>. Same boundary the default <code>MobileBreakpoint=768</code> on <code>OverlayOptions</code> checks.</td>
                        </tr>
                        <tr>
                            <td class="p-3 font-mono text-xs text-primary">IsTablet</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">bool</td>
                            <td class="p-3 text-muted-foreground">True when <code>Current</code> is <code>Md</code>.</td>
                        </tr>
                        <tr>
                            <td class="p-3 font-mono text-xs text-primary">IsDesktop</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">bool</td>
                            <td class="p-3 text-muted-foreground">True when <code>Current</code> is <code>Lg</code>, <code>Xl</code>, or <code>Xxl</code>.</td>
                        </tr>
                        <tr>
                            <td class="p-3 font-mono text-xs text-primary">ViewportChanged</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">event Action&lt;ViewportInfo&gt;</td>
                            <td class="p-3 text-muted-foreground">Fires on every (debounced) resize. <code>ViewportInfo</code> carries Width, Height, Current. Unsubscribe in <code>DisposeAsync</code>.</td>
                        </tr>
                        <tr>
                            <td class="p-3 font-mono text-xs text-primary">EnsureInitialisedAsync()</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">ValueTask</td>
                            <td class="p-3 text-muted-foreground">Lazily attaches the JS resize listener + pulls the initial viewport. Call eagerly from <code>OnAfterRenderAsync(firstRender: true)</code> to avoid the first-render zero-value read.</td>
                        </tr>
                    </tbody>
                </table>
            </Stack>
            <pre class="rounded-md border border-border/40 bg-muted/30 p-3 text-xs overflow-x-auto mt-3"><code>@@inject IResponsiveService Responsive
@@implements IAsyncDisposable

@@if (Responsive.IsMobile)
{
    &lt;BottomNav /&gt;
}
else
{
    &lt;Sidebar /&gt;
}

@@code {
    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            await Responsive.EnsureInitialisedAsync();
            Responsive.ViewportChanged += OnVp;
        }
    }

    private void OnVp(ViewportInfo vp) =&gt; InvokeAsync(StateHasChanged);

    public ValueTask DisposeAsync()
    {
        Responsive.ViewportChanged -= OnVp;
        return ValueTask.CompletedTask;
    }
}</code></pre>
        </Stack>

        <Stack>
            <Heading Level="3" Class="mb-3">AlertDialogOptions</Heading>
            <Stack Class="rounded-lg border border-border/40 overflow-x-auto">
                <table class="w-full min-w-[600px] text-sm">
                    <thead>
                        <tr class="border-b border-border/40 bg-muted/40">
                            <th class="text-left p-3 font-medium text-foreground">Property</th>
                            <th class="text-left p-3 font-medium text-foreground">Type</th>
                            <th class="text-left p-3 font-medium text-foreground">Default</th>
                            <th class="text-left p-3 font-medium text-foreground">Description</th>
                        </tr>
                    </thead>
                    <tbody class="divide-y divide-border/40">
                        <tr>
                            <td class="p-3 font-mono text-xs text-primary">Title</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">string</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">"Are you sure?"</td>
                            <td class="p-3 text-muted-foreground">The dialog heading text.</td>
                        </tr>
                        <tr>
                            <td class="p-3 font-mono text-xs text-primary">Description</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">string?</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">null</td>
                            <td class="p-3 text-muted-foreground">Optional body text below the title.</td>
                        </tr>
                        <tr>
                            <td class="p-3 font-mono text-xs text-primary">ConfirmText</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">string</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">"Continue"</td>
                            <td class="p-3 text-muted-foreground">Label for the confirm button.</td>
                        </tr>
                        <tr>
                            <td class="p-3 font-mono text-xs text-primary">CancelText</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">string</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">"Cancel"</td>
                            <td class="p-3 text-muted-foreground">Label for the cancel button.</td>
                        </tr>
                        <tr>
                            <td class="p-3 font-mono text-xs text-primary">IsDestructive</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">bool</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">false</td>
                            <td class="p-3 text-muted-foreground">When true, the confirm button uses destructive styling.</td>
                        </tr>
                    </tbody>
                </table>
            </Stack>
        </Stack>

    </Stack>
</Stack>

@inject OverlayService OverlayService

@code {
    private string? _dialogResult;
    private string? _sheetResult;
    private string? _drawerResult;
    private string? _alertResult;
    private bool _alertCancelled;

    private async Task ShowDialog()
    {
        _dialogResult = null;
        var result = await OverlayService.ShowDialogAsync<OverlayDemoContent>("Edit Profile");
        _dialogResult = result.Cancelled ? "Cancelled" : (result.Data?.ToString() ?? "Submitted");
    }

    private async Task ShowSheet(SheetSide side)
    {
        _sheetResult = null;
        var result = await OverlayService.ShowSheetAsync<OverlayDemoContent>("Edit Profile", side);
        _sheetResult = result.Cancelled ? "Cancelled" : (result.Data?.ToString() ?? "Submitted");
    }

    private async Task ShowDrawer()
    {
        _drawerResult = null;
        var result = await OverlayService.ShowDrawerAsync<OverlayDemoContent>("Edit Profile");
        _drawerResult = result.Cancelled ? "Cancelled" : (result.Data?.ToString() ?? "Submitted");
    }

    private async Task ShowConfirm()
    {
        _alertResult = null;
        var result = await OverlayService.ShowAlertDialogAsync(new AlertDialogOptions
        {
            Title = "Save changes?",
            Description = "This will overwrite your existing data.",
            ConfirmText = "Save",
            CancelText = "Cancel"
        });
        _alertCancelled = result.Cancelled;
        _alertResult = result.Cancelled ? "Cancelled" : "Confirmed";
    }

    private async Task ShowDestructive()
    {
        _alertResult = null;
        var result = await OverlayService.ShowAlertDialogAsync(new AlertDialogOptions
        {
            Title = "Delete item?",
            Description = "This action cannot be undone.",
            ConfirmText = "Delete",
            CancelText = "Cancel",
            IsDestructive = true
        });
        _alertCancelled = result.Cancelled;
        _alertResult = result.Cancelled ? "Cancelled" : "Deleted";
    }

    private string _dialogCode =
        """
        @inject OverlayService OverlayService

        <Stack Gap="3">
            <Button OnClick="OpenDialog">Open Dialog</Button>
            @if (_result is not null)
            {
                <Alert>Result: @_result</Alert>
            }
        </Stack>

        @code {
            private string? _result;

            private async Task OpenDialog()
            {
                _result = null;
                var overlayResult = await OverlayService.ShowDialogAsync<ProfileFormContent>("Edit Profile");
                _result = overlayResult.Cancelled ? "Cancelled" : $"Submitted: {overlayResult.Data}";
            }
        }

        // ProfileFormContent.razor — receives OverlayReference as a CascadingParameter
        @namespace YourApp

        <Stack Gap="4" Class="py-4">
            <Stack Gap="2">
                <Label>Name</Label>
                <Input @bind-Value="_name" Placeholder="Enter your name..." />
            </Stack>
            <Stack Gap="2">
                <Label>Email</Label>
                <Input @bind-Value="_email" Placeholder="Enter your email..." />
            </Stack>
            <Flex Justify="end" Gap="2" Class="pt-2">
                <Button Variant="Button.ButtonVariant.Outline" OnClick="() => Overlay.Cancel()">Cancel</Button>
                <Button OnClick="Submit">Submit</Button>
            </Flex>
        </Stack>

        @code {
            [CascadingParameter] public OverlayReference Overlay { get; set; } = default!;

            private string _name = "";
            private string _email = "";

            private void Submit() => Overlay.Close(new { Name = _name, Email = _email });
        }
        """;

    private string _sheetCode =
        """
        @inject OverlayService OverlayService

        <Flex Gap="2" Wrap="true">
            <Button Variant="Button.ButtonVariant.Outline" OnClick="() => OpenSheet(SheetSide.Right)">Right</Button>
            <Button Variant="Button.ButtonVariant.Outline" OnClick="() => OpenSheet(SheetSide.Left)">Left</Button>
            <Button Variant="Button.ButtonVariant.Outline" OnClick="() => OpenSheet(SheetSide.Bottom)">Bottom</Button>
        </Flex>
        @if (_result is not null)
        {
            <Alert>Result: @_result</Alert>
        }

        @code {
            private string? _result;

            private async Task OpenSheet(SheetSide side)
            {
                _result = null;
                var overlayResult = await OverlayService.ShowSheetAsync<ProfileFormContent>(
                    title: "Edit Profile",
                    side: side,
                    size: SheetSize.Default);
                _result = overlayResult.Cancelled ? "Cancelled" : $"Submitted: {overlayResult.Data}";
            }
        }
        """;

    private string _drawerCode =
        """
        @inject OverlayService OverlayService

        <Stack Gap="3">
            <Button Variant="Button.ButtonVariant.Outline" OnClick="OpenDrawer">Open Drawer</Button>
            @if (_result is not null)
            {
                <Alert>Result: @_result</Alert>
            }
        </Stack>

        @code {
            private string? _result;

            private async Task OpenDrawer()
            {
                _result = null;
                var overlayResult = await OverlayService.ShowDrawerAsync<ProfileFormContent>("Edit Profile");
                _result = overlayResult.Cancelled ? "Cancelled" : $"Submitted: {overlayResult.Data}";
            }
        }
        """;

    private string _alertCode =
        """
        @inject OverlayService OverlayService

        <Button OnClick="DeleteItem">Delete Item</Button>

        @code {
            private async Task DeleteItem()
            {
                var result = await OverlayService.ShowAlertDialogAsync(new AlertDialogOptions
                {
                    Title = "Delete item?",
                    Description = "This action cannot be undone.",
                    ConfirmText = "Delete",
                    IsDestructive = true
                });

                if (!result.Cancelled)
                {
                    // proceed with deletion
                }
            }
        }
        """;
}
