{
  "name": "Overlay",
  "category": "Overlay",
  "subcategory": null,
  "description": "Low-level backdrop primitive for custom popovers and modals.",
  "thumbnail": "/preview-cards/overlay.png",
  "hasDocsPage": true,
  "nugetPackage": "Lumeo",
  "files": [
    "UI/Overlay/OverlayProvider.razor"
  ],
  "dependencies": [
    "alert-dialog",
    "button",
    "dialog",
    "drawer",
    "sheet"
  ],
  "packageDependencies": [],
  "cssVars": [
    "--color-foreground"
  ],
  "api": {
    "name": "Overlay",
    "category": "Overlay",
    "subcategory": null,
    "description": "Low-level backdrop primitive for custom popovers and modals.",
    "nugetPackage": "Lumeo",
    "files": [
      "UI/Overlay/OverlayProvider.razor"
    ],
    "namespace": "Lumeo",
    "inheritsFrom": null,
    "implements": [
      "IAsyncDisposable"
    ],
    "parameters": [],
    "events": [],
    "enums": [],
    "records": [],
    "cssVars": [
      "--color-foreground"
    ],
    "examples": [
      {
        "title": "Open a Dialog",
        "code": "@inject OverlayService OverlayService\n\n<Button OnClick=\"@OpenDialog\">Open Dialog</Button>\n\n@code {\n    private async Task OpenDialog()\n    {\n        var result = await OverlayService.ShowDialogAsync<MyDialogContent>(\n            title: \"Edit Profile\",\n            parameters: new OverlayParameters().Add(\"UserId\", 42));\n\n        if (!result.Cancelled) { /* handle result */ }\n    }\n}"
      },
      {
        "title": "Open a Sheet",
        "code": "@inject OverlayService OverlayService\n\n<Button OnClick=\"@OpenSheet\">Open Sheet</Button>\n\n@code {\n    private async Task OpenSheet()\n    {\n        await OverlayService.ShowSheetAsync<MySheetContent>(\n            title: \"Settings\",\n            side: SheetSide.Right);\n    }\n}"
      },
      {
        "title": "Confirmation Dialog",
        "code": "@inject OverlayService OverlayService\n\n<Button Variant=\"Button.ButtonVariant.Destructive\" OnClick=\"@Confirm\">Delete</Button>\n\n@code {\n    private async Task Confirm()\n    {\n        var result = await OverlayService.ShowAlertDialogAsync(new AlertDialogOptions\n        {\n            Title = \"Delete Item?\",\n            Description = \"This action cannot be undone.\",\n            ConfirmText = \"Delete\",\n            CancelText = \"Cancel\",\n            IsDestructive = true\n        });\n\n        if (!result.Cancelled) { /* perform delete */ }\n    }\n}"
      }
    ],
    "subComponents": {},
    "parseFailed": false,
    "parseError": null
  },
  "$schema": "https://lumeo.nativ.sh/registry-component-schema.json",
  "key": "overlay",
  "docsUrl": "https://lumeo.nativ.sh/components/overlay",
  "sourceUrl": [
    {
      "file": "UI/Overlay/OverlayProvider.razor",
      "url": "https://github.com/Brain2k-0005/Lumeo/tree/master/src/Lumeo/UI/Overlay/OverlayProvider.razor"
    }
  ],
  "source": [
    {
      "path": "UI/Overlay/OverlayProvider.razor",
      "content": "@namespace Lumeo\n@using Lumeo.Services\n@implements IAsyncDisposable\n\n@foreach (var overlay in _overlays)\n{\n    @switch (overlay.Type)\n    {\n        case OverlayType.Dialog:\n            <Dialog @key=\"overlay.Id\" Open=\"true\" OpenChanged=\"(bool val) => OnOverlayClosed(val, overlay.Id)\">\n                <DialogContent PreventClose=\"@overlay.Options.PreventClose\" Class=\"@overlay.Options.Class\">\n                    @if (overlay.Title is not null)\n                    {\n                        <DialogHeader>\n                            <DialogTitle>@overlay.Title</DialogTitle>\n                        </DialogHeader>\n                    }\n                    <CascadingValue Value=\"@(new OverlayShellMarker(overlay.Id))\" IsFixed=\"true\">\n                        <CascadingValue Value=\"@GetOrCreateReference(overlay)\" IsFixed=\"true\">\n                            <DynamicComponent Type=\"@GetComponentType(overlay)\" Parameters=\"@GetParameters(overlay)\" />\n                        </CascadingValue>\n                    </CascadingValue>\n                </DialogContent>\n            </Dialog>\n            break;\n\n        case OverlayType.Sheet:\n            <Sheet @key=\"overlay.Id\" Open=\"true\" OpenChanged=\"(bool val) => OnOverlayClosed(val, overlay.Id)\">\n                <SheetContent Side=\"@MapSheetSide(overlay.Options.SheetSide)\" Size=\"@MapSheetSize(overlay.Options.SheetSize)\" PreventClose=\"@overlay.Options.PreventClose\" Class=\"@overlay.Options.Class\">\n                    @if (overlay.Title is not null)\n                    {\n                        <SheetHeader>\n                            <SheetTitle>@overlay.Title</SheetTitle>\n                        </SheetHeader>\n                    }\n                    <CascadingValue Value=\"@(new OverlayShellMarker(overlay.Id))\" IsFixed=\"true\">\n                        <CascadingValue Value=\"@GetOrCreateReference(overlay)\" IsFixed=\"true\">\n                            <DynamicComponent Type=\"@GetComponentType(overlay)\" Parameters=\"@GetParameters(overlay)\" />\n                        </CascadingValue>\n                    </CascadingValue>\n                </SheetContent>\n            </Sheet>\n            break;\n\n        case OverlayType.Drawer:\n            <Drawer @key=\"overlay.Id\" Open=\"true\" OpenChanged=\"(bool val) => OnOverlayClosed(val, overlay.Id)\">\n                <DrawerContent PreventClose=\"@overlay.Options.PreventClose\" Class=\"@overlay.Options.Class\">\n                    @if (overlay.Title is not null)\n                    {\n                        <DrawerHeader>\n                            <DrawerTitle>@overlay.Title</DrawerTitle>\n                        </DrawerHeader>\n                    }\n                    <CascadingValue Value=\"@(new OverlayShellMarker(overlay.Id))\" IsFixed=\"true\">\n                        <CascadingValue Value=\"@GetOrCreateReference(overlay)\" IsFixed=\"true\">\n                            <DynamicComponent Type=\"@GetComponentType(overlay)\" Parameters=\"@GetParameters(overlay)\" />\n                        </CascadingValue>\n                    </CascadingValue>\n                </DrawerContent>\n            </Drawer>\n            break;\n\n        case OverlayType.AlertDialog:\n            <AlertDialog @key=\"overlay.Id\" Open=\"true\">\n                <AlertDialogContent>\n                    <AlertDialogHeader>\n                        <AlertDialogTitle>@(overlay.AlertOptions?.Title ?? \"Are you sure?\")</AlertDialogTitle>\n                        @if (overlay.AlertOptions?.Description is not null)\n                        {\n                            <AlertDialogDescription>@overlay.AlertOptions.Description</AlertDialogDescription>\n                        }\n                    </AlertDialogHeader>\n                    <AlertDialogFooter>\n                        <AlertDialogCancel @onclick=\"() => HandleCancel(overlay.Id)\">@(overlay.AlertOptions?.CancelText ?? \"Cancel\")</AlertDialogCancel>\n                        @if (overlay.AlertOptions?.IsDestructive == true)\n                        {\n                            <AlertDialogAction OnAction=\"() => HandleConfirm(overlay.Id)\">@(overlay.AlertOptions?.ConfirmText ?? \"Continue\")</AlertDialogAction>\n                        }\n                        else\n                        {\n                            <Button OnClick=\"() => HandleConfirm(overlay.Id)\">@(overlay.AlertOptions?.ConfirmText ?? \"Continue\")</Button>\n                        }\n                    </AlertDialogFooter>\n                </AlertDialogContent>\n            </AlertDialog>\n            break;\n    }\n}\n\n@inject OverlayService OverlayService\n\n@code {\n    private readonly List<OverlayInstance> _overlays = new();\n    private readonly Dictionary<string, OverlayReference> _referenceCache = new();\n\n    protected override void OnInitialized()\n    {\n        OverlayService.OnShow += HandleShow;\n        OverlayService.OnClose += HandleClose;\n    }\n\n    private void HandleShow(OverlayInstance instance)\n    {\n        SafeAsyncDispatcher.FireAndForget(InvokeAsync, () => HandleShowAsync(instance), \"OverlayProvider.HandleShow\");\n    }\n\n    private Task HandleShowAsync(OverlayInstance instance)\n    {\n        _overlays.Add(instance);\n        // Pre-cache the reference so the CascadingValue always receives the same\n        // object reference for the lifetime of this overlay (prevents subtree re-renders).\n        _referenceCache[instance.Id] = new OverlayReference(instance.Id, instance.Parameters, OverlayService);\n        StateHasChanged();\n        return Task.CompletedTask;\n    }\n\n    private void HandleClose(string id, object? result, bool cancelled)\n    {\n        SafeAsyncDispatcher.FireAndForget(InvokeAsync, () => HandleCloseAsync(id, result, cancelled), \"OverlayProvider.HandleClose\");\n    }\n\n    private Task HandleCloseAsync(string id, object? result, bool cancelled)\n    {\n        var overlay = _overlays.FirstOrDefault(o => o.Id == id);\n        if (overlay is null) return Task.CompletedTask;\n\n        _overlays.Remove(overlay);\n        _referenceCache.Remove(id);\n\n        if (cancelled)\n            overlay.Tcs.TrySetResult(OverlayResult.CancelResult());\n        else\n            overlay.Tcs.TrySetResult(OverlayResult.Ok(result));\n\n        StateHasChanged();\n        return Task.CompletedTask;\n    }\n\n    private void OnOverlayClosed(bool isOpen, string id)\n    {\n        if (!isOpen) OverlayService.Cancel(id);\n    }\n\n    private void HandleConfirm(string id)\n    {\n        OverlayService.Close(id, true);\n    }\n\n    private void HandleCancel(string id)\n    {\n        OverlayService.Cancel(id);\n    }\n\n    private static Type GetComponentType(OverlayInstance overlay) => overlay.ComponentType ?? typeof(Fallback);\n    private static Dictionary<string, object>? GetParameters(OverlayInstance overlay) => overlay.Parameters?.ToDictionary();\n\n    private class Fallback : Microsoft.AspNetCore.Components.ComponentBase { }\n\n    private OverlayReference GetOrCreateReference(OverlayInstance overlay)\n    {\n        if (!_referenceCache.TryGetValue(overlay.Id, out var reference))\n        {\n            reference = new OverlayReference(overlay.Id, overlay.Parameters, OverlayService);\n            _referenceCache[overlay.Id] = reference;\n        }\n        return reference;\n    }\n\n    private static SheetContent.SheetSide MapSheetSide(SheetSide side) => side switch\n    {\n        SheetSide.Top => SheetContent.SheetSide.Top,\n        SheetSide.Bottom => SheetContent.SheetSide.Bottom,\n        SheetSide.Left => SheetContent.SheetSide.Left,\n        _ => SheetContent.SheetSide.Right\n    };\n\n    private static SheetContent.SheetSize MapSheetSize(SheetSize size) => size switch\n    {\n        SheetSize.Sm => SheetContent.SheetSize.Sm,\n        SheetSize.Lg => SheetContent.SheetSize.Lg,\n        SheetSize.Xl => SheetContent.SheetSize.Xl,\n        SheetSize.Full => SheetContent.SheetSize.Full,\n        _ => SheetContent.SheetSize.Default\n    };\n\n    public async ValueTask DisposeAsync()\n    {\n        OverlayService.OnShow -= HandleShow;\n        OverlayService.OnClose -= HandleClose;\n\n        foreach (var overlay in _overlays)\n        {\n            overlay.Tcs.TrySetResult(OverlayResult.CancelResult());\n        }\n        _overlays.Clear();\n        _referenceCache.Clear();\n        await Task.CompletedTask;\n    }\n}\n"
    }
  ],
  "slots": [],
  "serviceDependencies": [
    {
      "service": "OverlayService",
      "namespace": ""
    }
  ],
  "cascadingDependencies": [],
  "relatedComponents": [
    {
      "name": "OverlayProvider",
      "reason": "sub-component"
    },
    {
      "name": "Dialog",
      "reason": "used internally"
    },
    {
      "name": "Sheet",
      "reason": "used internally"
    },
    {
      "name": "Drawer",
      "reason": "used internally"
    },
    {
      "name": "AlertDialog",
      "reason": "used internally"
    },
    {
      "name": "Button",
      "reason": "used internally"
    }
  ],
  "keyboardInteractions": [],
  "tests": [
    "tests/Lumeo.Tests/Components/Overlay/OverlayProviderTests.cs",
    "tests/Lumeo.Tests/Contract/ComponentContractTests.cs"
  ],
  "mdSummary": "# Overlay\n\nLow-level backdrop primitive for custom popovers and modals.\n\n**Package:** `Lumeo` · **Category:** Overlay\n**Docs:** https://lumeo.nativ.sh/components/overlay\n\n## Parameters\n| Owner | Name | Type | Default | Description |\n|---|---|---|---|---|\n\n## Slots\n- (none)\n\n## Events\n- (none)\n\n## Sub-components\n- `OverlayProvider`\n\n## Cascading values it expects\n- (none)\n\n## Services it injects\n- `OverlayService` ()\n\n## Keyboard\n—\n\n## Example\n```razor\n<Overlay />\n```\n\n## CSS variables\n`--color-foreground`\n\n## Files\n- `UI/Overlay/OverlayProvider.razor`\n"
}