{
  "name": "Drawer",
  "category": "Overlay",
  "subcategory": null,
  "description": "Slide-up sheet for mobile-first contextual content.",
  "thumbnail": "/preview-cards/drawer.png",
  "hasDocsPage": true,
  "nugetPackage": "Lumeo",
  "files": [
    "UI/Drawer/Drawer.razor",
    "UI/Drawer/DrawerClose.razor",
    "UI/Drawer/DrawerContent.razor",
    "UI/Drawer/DrawerDescription.razor",
    "UI/Drawer/DrawerFooter.razor",
    "UI/Drawer/DrawerHeader.razor",
    "UI/Drawer/DrawerTitle.razor",
    "UI/Drawer/DrawerTrigger.razor"
  ],
  "dependencies": [],
  "packageDependencies": [],
  "cssVars": [
    "--color-background",
    "--color-muted",
    "--color-muted-foreground",
    "--radius"
  ],
  "api": {
    "name": "Drawer",
    "category": "Overlay",
    "subcategory": null,
    "description": "Slide-up sheet for mobile-first contextual content.",
    "nugetPackage": "Lumeo",
    "files": [
      "UI/Drawer/Drawer.razor",
      "UI/Drawer/DrawerClose.razor",
      "UI/Drawer/DrawerContent.razor",
      "UI/Drawer/DrawerDescription.razor",
      "UI/Drawer/DrawerFooter.razor",
      "UI/Drawer/DrawerHeader.razor",
      "UI/Drawer/DrawerTitle.razor",
      "UI/Drawer/DrawerTrigger.razor"
    ],
    "namespace": "Lumeo",
    "inheritsFrom": null,
    "implements": [],
    "parameters": [
      {
        "name": "ChildContent",
        "type": "RenderFragment?",
        "default": null,
        "description": null,
        "isCascading": false,
        "captureUnmatched": false
      },
      {
        "name": "Open",
        "type": "bool",
        "default": null,
        "description": null,
        "isCascading": false,
        "captureUnmatched": false
      },
      {
        "name": "OpenChanged",
        "type": "EventCallback<bool>",
        "default": null,
        "description": null,
        "isCascading": false,
        "captureUnmatched": false
      },
      {
        "name": "IsOpen",
        "type": "bool",
        "default": null,
        "description": null,
        "isCascading": false,
        "captureUnmatched": false
      },
      {
        "name": "IsOpenChanged",
        "type": "EventCallback<bool>",
        "default": null,
        "description": null,
        "isCascading": false,
        "captureUnmatched": false
      }
    ],
    "events": [
      {
        "name": "OpenChanged",
        "type": "EventCallback<bool>",
        "description": null
      },
      {
        "name": "IsOpenChanged",
        "type": "EventCallback<bool>",
        "description": null
      }
    ],
    "enums": [],
    "records": [
      {
        "name": "DrawerContext",
        "signature": "DrawerContext(bool IsOpen, EventCallback<bool> SetOpen, string TitleId, string DescriptionId)",
        "description": null
      }
    ],
    "cssVars": [
      "--color-background",
      "--color-muted",
      "--color-muted-foreground",
      "--radius"
    ],
    "examples": [
      {
        "title": "Default",
        "code": "<Drawer @bind-Open=\"_isOpen\">\n    <DrawerTrigger>\n        <Button Variant=\"Button.ButtonVariant.Outline\">Open Drawer</Button>\n    </DrawerTrigger>\n    <DrawerContent>\n        <DrawerHeader>\n            <DrawerTitle>Move Goal</DrawerTitle>\n            <DrawerDescription>Set your daily activity goal.</DrawerDescription>\n        </DrawerHeader>\n        <Stack Gap=\"0\" Class=\"p-4 text-center\">\n            <Lumeo.Text Size=\"5xl\" Weight=\"bold\">@_goal</Lumeo.Text>\n            <Lumeo.Text Size=\"sm\" Color=\"muted\">calories/day</Lumeo.Text>\n        </Stack>\n        <DrawerFooter>\n            <DrawerClose>\n                <Button Class=\"w-full\">Submit</Button>\n            </DrawerClose>\n            <DrawerClose>\n                <Button Variant=\"Button.ButtonVariant.Outline\" Class=\"w-full\">Cancel</Button>\n            </DrawerClose>\n        </DrawerFooter>\n    </DrawerContent>\n</Drawer>\n\n@code {\n    private bool _isOpen;\n    private int _goal = 350;\n}"
      },
      {
        "title": "Filters Drawer",
        "code": "<Drawer @bind-Open=\"_isFiltersOpen\">\n    <DrawerTrigger>\n        <Button Variant=\"Button.ButtonVariant.Outline\">\n            <Blazicon Svg=\"Lucide.Settings\" class=\"h-4 w-4\" /> Filters\n        </Button>\n    </DrawerTrigger>\n    <DrawerContent>\n        <DrawerHeader>\n            <DrawerTitle>Filter Results</DrawerTitle>\n            <DrawerDescription>Narrow down your search.</DrawerDescription>\n        </DrawerHeader>\n        <Stack Gap=\"4\" Class=\"p-4\">\n            <Select @bind-Value=\"_filterCategory\">\n                <SelectTrigger><span>@(_filterCategory ?? \"All categories\")</span></SelectTrigger>\n                <SelectContent>\n                    <SelectItem Value=\"electronics\">Electronics</SelectItem>\n                    <SelectItem Value=\"clothing\">Clothing</SelectItem>\n                </SelectContent>\n            </Select>\n        </Stack>\n        <DrawerFooter>\n            <DrawerClose><Button Class=\"w-full\">Apply Filters</Button></DrawerClose>\n        </DrawerFooter>\n    </DrawerContent>\n</Drawer>"
      },
      {
        "title": "Prevent Close",
        "code": "<Drawer @bind-Open=\"_preventDrawerOpen\">\n    <DrawerTrigger>\n        <Button Variant=\"Button.ButtonVariant.Outline\">Open Protected Drawer</Button>\n    </DrawerTrigger>\n    <DrawerContent PreventClose=\"true\">\n        <DrawerHeader>\n            <DrawerTitle>Confirm Action</DrawerTitle>\n            <DrawerDescription>You must choose an option to continue.</DrawerDescription>\n        </DrawerHeader>\n        <Stack Gap=\"2\" Class=\"p-4\">\n            <Button Class=\"w-full\" OnClick=\"@(() => _preventDrawerOpen = false)\">Confirm</Button>\n            <Button Variant=\"Button.ButtonVariant.Outline\" Class=\"w-full\" OnClick=\"@(() => _preventDrawerOpen = false)\">Cancel</Button>\n        </Stack>\n    </DrawerContent>\n</Drawer>\n\n@code {\n    private bool _preventDrawerOpen;\n}"
      },
      {
        "title": "Side — interactive",
        "code": "<Segmented @bind-Value=\"_drawerSideSel\" Options=\"_drawerSideOptions\" />\n<Drawer @bind-Open=\"_open\">\n    <DrawerTrigger>\n        <Button Variant=\"Button.ButtonVariant.Outline\">Open Drawer (@_drawerSideSel)</Button>\n    </DrawerTrigger>\n    <DrawerContent Side=\"@_activeDrawerSide\">\n        <DrawerHeader>\n            <DrawerTitle>@_drawerSideSel Drawer</DrawerTitle>\n            <DrawerDescription>Slides in from the @_drawerSideSel.ToLower().</DrawerDescription>\n        </DrawerHeader>\n        <DrawerFooter>\n            <DrawerClose><Button Class=\"w-full\">Close</Button></DrawerClose>\n        </DrawerFooter>\n    </DrawerContent>\n</Drawer>\n\n@code {\n    private string _drawerSideSel = \"Bottom\";\n    private DrawerContent.DrawerSide _activeDrawerSide => Enum.Parse<DrawerContent.DrawerSide>(_drawerSideSel);\n    private List<Segmented.SegmentedOption> _drawerSideOptions = new()\n    {\n        new() { Label = \"Top\", Value = \"Top\" },\n        new() { Label = \"Right\", Value = \"Right\" },\n        new() { Label = \"Bottom\", Value = \"Bottom\" },\n        new() { Label = \"Left\", Value = \"Left\" },\n    };\n}"
      }
    ],
    "subComponents": {
      "DrawerClose": {
        "componentName": "DrawerClose",
        "fileName": "DrawerClose.razor",
        "namespace": "Lumeo",
        "inheritsFrom": null,
        "implements": [],
        "parameters": [
          {
            "name": "Context",
            "type": "Drawer.DrawerContext",
            "default": "default!",
            "description": null,
            "isCascading": true,
            "captureUnmatched": false
          },
          {
            "name": "ChildContent",
            "type": "RenderFragment?",
            "default": null,
            "description": null,
            "isCascading": false,
            "captureUnmatched": false
          },
          {
            "name": "Class",
            "type": "string?",
            "default": null,
            "description": null,
            "isCascading": false,
            "captureUnmatched": false
          },
          {
            "name": "AdditionalAttributes",
            "type": "Dictionary<string, object>?",
            "default": null,
            "description": null,
            "isCascading": false,
            "captureUnmatched": true
          }
        ],
        "events": [],
        "enums": [],
        "records": [],
        "parseFailed": false,
        "parseError": null
      },
      "DrawerContent": {
        "componentName": "DrawerContent",
        "fileName": "DrawerContent.razor",
        "namespace": "Lumeo",
        "inheritsFrom": null,
        "implements": [
          "IAsyncDisposable"
        ],
        "parameters": [
          {
            "name": "Context",
            "type": "Drawer.DrawerContext",
            "default": "default!",
            "description": null,
            "isCascading": true,
            "captureUnmatched": false
          },
          {
            "name": "Shell",
            "type": "OverlayShellMarker?",
            "default": null,
            "description": null,
            "isCascading": true,
            "captureUnmatched": false
          },
          {
            "name": "ChildContent",
            "type": "RenderFragment?",
            "default": null,
            "description": null,
            "isCascading": false,
            "captureUnmatched": false
          },
          {
            "name": "Side",
            "type": "DrawerSide",
            "default": "DrawerSide.Bottom",
            "description": null,
            "isCascading": false,
            "captureUnmatched": false
          },
          {
            "name": "Animation",
            "type": "DrawerAnimation",
            "default": "DrawerAnimation.Slide",
            "description": null,
            "isCascading": false,
            "captureUnmatched": false
          },
          {
            "name": "PreventClose",
            "type": "bool",
            "default": null,
            "description": null,
            "isCascading": false,
            "captureUnmatched": false
          },
          {
            "name": "Class",
            "type": "string?",
            "default": null,
            "description": null,
            "isCascading": false,
            "captureUnmatched": false
          },
          {
            "name": "AdditionalAttributes",
            "type": "Dictionary<string, object>?",
            "default": null,
            "description": null,
            "isCascading": false,
            "captureUnmatched": true
          }
        ],
        "events": [],
        "enums": [
          {
            "name": "DrawerSide",
            "values": [
              "Top",
              "Right",
              "Bottom",
              "Left"
            ],
            "description": null
          },
          {
            "name": "DrawerAnimation",
            "values": [
              "Slide",
              "Fade",
              "None"
            ],
            "description": null
          }
        ],
        "records": [],
        "parseFailed": false,
        "parseError": null
      },
      "DrawerDescription": {
        "componentName": "DrawerDescription",
        "fileName": "DrawerDescription.razor",
        "namespace": "Lumeo",
        "inheritsFrom": null,
        "implements": [],
        "parameters": [
          {
            "name": "Context",
            "type": "Drawer.DrawerContext",
            "default": "default!",
            "description": null,
            "isCascading": true,
            "captureUnmatched": false
          },
          {
            "name": "ChildContent",
            "type": "RenderFragment?",
            "default": null,
            "description": null,
            "isCascading": false,
            "captureUnmatched": false
          },
          {
            "name": "Class",
            "type": "string?",
            "default": null,
            "description": null,
            "isCascading": false,
            "captureUnmatched": false
          },
          {
            "name": "AdditionalAttributes",
            "type": "Dictionary<string, object>?",
            "default": null,
            "description": null,
            "isCascading": false,
            "captureUnmatched": true
          }
        ],
        "events": [],
        "enums": [],
        "records": [],
        "parseFailed": false,
        "parseError": null
      },
      "DrawerFooter": {
        "componentName": "DrawerFooter",
        "fileName": "DrawerFooter.razor",
        "namespace": "Lumeo",
        "inheritsFrom": null,
        "implements": [],
        "parameters": [
          {
            "name": "ChildContent",
            "type": "RenderFragment?",
            "default": null,
            "description": null,
            "isCascading": false,
            "captureUnmatched": false
          },
          {
            "name": "Class",
            "type": "string?",
            "default": null,
            "description": null,
            "isCascading": false,
            "captureUnmatched": false
          },
          {
            "name": "AdditionalAttributes",
            "type": "Dictionary<string, object>?",
            "default": null,
            "description": null,
            "isCascading": false,
            "captureUnmatched": true
          }
        ],
        "events": [],
        "enums": [],
        "records": [],
        "parseFailed": false,
        "parseError": null
      },
      "DrawerHeader": {
        "componentName": "DrawerHeader",
        "fileName": "DrawerHeader.razor",
        "namespace": "Lumeo",
        "inheritsFrom": null,
        "implements": [],
        "parameters": [
          {
            "name": "ChildContent",
            "type": "RenderFragment?",
            "default": null,
            "description": null,
            "isCascading": false,
            "captureUnmatched": false
          },
          {
            "name": "Class",
            "type": "string?",
            "default": null,
            "description": null,
            "isCascading": false,
            "captureUnmatched": false
          },
          {
            "name": "AdditionalAttributes",
            "type": "Dictionary<string, object>?",
            "default": null,
            "description": null,
            "isCascading": false,
            "captureUnmatched": true
          }
        ],
        "events": [],
        "enums": [],
        "records": [],
        "parseFailed": false,
        "parseError": null
      },
      "DrawerTitle": {
        "componentName": "DrawerTitle",
        "fileName": "DrawerTitle.razor",
        "namespace": "Lumeo",
        "inheritsFrom": null,
        "implements": [],
        "parameters": [
          {
            "name": "Context",
            "type": "Drawer.DrawerContext",
            "default": "default!",
            "description": null,
            "isCascading": true,
            "captureUnmatched": false
          },
          {
            "name": "ChildContent",
            "type": "RenderFragment?",
            "default": null,
            "description": null,
            "isCascading": false,
            "captureUnmatched": false
          },
          {
            "name": "Class",
            "type": "string?",
            "default": null,
            "description": null,
            "isCascading": false,
            "captureUnmatched": false
          },
          {
            "name": "AdditionalAttributes",
            "type": "Dictionary<string, object>?",
            "default": null,
            "description": null,
            "isCascading": false,
            "captureUnmatched": true
          }
        ],
        "events": [],
        "enums": [],
        "records": [],
        "parseFailed": false,
        "parseError": null
      },
      "DrawerTrigger": {
        "componentName": "DrawerTrigger",
        "fileName": "DrawerTrigger.razor",
        "namespace": "Lumeo",
        "inheritsFrom": null,
        "implements": [],
        "parameters": [
          {
            "name": "Context",
            "type": "Drawer.DrawerContext",
            "default": "default!",
            "description": null,
            "isCascading": true,
            "captureUnmatched": false
          },
          {
            "name": "ChildContent",
            "type": "RenderFragment?",
            "default": null,
            "description": null,
            "isCascading": false,
            "captureUnmatched": false
          },
          {
            "name": "Class",
            "type": "string?",
            "default": null,
            "description": null,
            "isCascading": false,
            "captureUnmatched": false
          },
          {
            "name": "AdditionalAttributes",
            "type": "Dictionary<string, object>?",
            "default": null,
            "description": null,
            "isCascading": false,
            "captureUnmatched": true
          }
        ],
        "events": [],
        "enums": [],
        "records": [],
        "parseFailed": false,
        "parseError": null
      }
    },
    "parseFailed": false,
    "parseError": null
  },
  "$schema": "https://lumeo.nativ.sh/registry-component-schema.json",
  "key": "drawer",
  "docsUrl": "https://lumeo.nativ.sh/components/drawer",
  "sourceUrl": [
    {
      "file": "UI/Drawer/Drawer.razor",
      "url": "https://github.com/Brain2k-0005/Lumeo/tree/master/src/Lumeo/UI/Drawer/Drawer.razor"
    },
    {
      "file": "UI/Drawer/DrawerClose.razor",
      "url": "https://github.com/Brain2k-0005/Lumeo/tree/master/src/Lumeo/UI/Drawer/DrawerClose.razor"
    },
    {
      "file": "UI/Drawer/DrawerContent.razor",
      "url": "https://github.com/Brain2k-0005/Lumeo/tree/master/src/Lumeo/UI/Drawer/DrawerContent.razor"
    },
    {
      "file": "UI/Drawer/DrawerDescription.razor",
      "url": "https://github.com/Brain2k-0005/Lumeo/tree/master/src/Lumeo/UI/Drawer/DrawerDescription.razor"
    },
    {
      "file": "UI/Drawer/DrawerFooter.razor",
      "url": "https://github.com/Brain2k-0005/Lumeo/tree/master/src/Lumeo/UI/Drawer/DrawerFooter.razor"
    },
    {
      "file": "UI/Drawer/DrawerHeader.razor",
      "url": "https://github.com/Brain2k-0005/Lumeo/tree/master/src/Lumeo/UI/Drawer/DrawerHeader.razor"
    },
    {
      "file": "UI/Drawer/DrawerTitle.razor",
      "url": "https://github.com/Brain2k-0005/Lumeo/tree/master/src/Lumeo/UI/Drawer/DrawerTitle.razor"
    },
    {
      "file": "UI/Drawer/DrawerTrigger.razor",
      "url": "https://github.com/Brain2k-0005/Lumeo/tree/master/src/Lumeo/UI/Drawer/DrawerTrigger.razor"
    }
  ],
  "source": [
    {
      "path": "UI/Drawer/Drawer.razor",
      "content": "@namespace Lumeo\n\n@{\n    var context = new DrawerContext(Open, EventCallback.Factory.Create<bool>(this, SetOpen), _titleId, _descriptionId);\n}\n\n<CascadingValue Value=\"context\" IsFixed=\"false\">\n    @ChildContent\n</CascadingValue>\n\n@code {\n    [Parameter] public RenderFragment? ChildContent { get; set; }\n    [Parameter] public bool Open { get; set; }\n    [Parameter] public EventCallback<bool> OpenChanged { get; set; }\n\n    [Obsolete(\"Use Open instead. IsOpen will be removed in a future release.\")]\n    [Parameter] public bool IsOpen { get => Open; set => Open = value; }\n\n    [Obsolete(\"Use OpenChanged instead. IsOpenChanged will be removed in a future release.\")]\n    [Parameter] public EventCallback<bool> IsOpenChanged { get => OpenChanged; set => OpenChanged = value; }\n\n    private readonly string _titleId = $\"drawer-title-{Guid.NewGuid():N}\";\n    private readonly string _descriptionId = $\"drawer-desc-{Guid.NewGuid():N}\";\n\n    private async Task SetOpen(bool value)\n    {\n        Open = value;\n        await OpenChanged.InvokeAsync(value);\n    }\n\n    public record DrawerContext(bool IsOpen, EventCallback<bool> SetOpen, string TitleId, string DescriptionId);\n}\n"
    },
    {
      "path": "UI/Drawer/DrawerClose.razor",
      "content": "@namespace Lumeo\n\n<div class=\"@CssClass\" @onclick=\"Close\" @attributes=\"AdditionalAttributes\">\n    @ChildContent\n</div>\n\n@code {\n    [CascadingParameter] public Drawer.DrawerContext Context { get; set; } = default!;\n    [Parameter] public RenderFragment? ChildContent { get; set; }\n    [Parameter] public string? Class { get; set; }\n    [Parameter(CaptureUnmatchedValues = true)] public Dictionary<string, object>? AdditionalAttributes { get; set; }\n\n    private string CssClass => $\"inline-flex {Class}\".Trim();\n\n    private async Task Close() => await Context.SetOpen.InvokeAsync(false);\n}\n"
    },
    {
      "path": "UI/Drawer/DrawerContent.razor",
      "content": "@namespace Lumeo\n@using Lumeo.Services\n@implements IAsyncDisposable\n\n@*\n    Animation=Slide is now safe (rc.21 fixed the transform trap), but\n    Animation=Fade or None still available for consumers who want maximum\n    predictability. The Slide keyframes were updated so they end at\n    `transform: none` rather than an identity-translate, which used to create\n    a CSS containing-block trap that broke `position: fixed` popovers\n    (Select/DatePicker/Combobox) rendered inside a Drawer.\n*@\n\n@if (Shell is not null)\n{\n    @* See OverlayShellMarker — host DrawerContent already painted the shell.\n       Pass children through to avoid a second backdrop + panel + swipe handler. *@\n    @ChildContent\n}\nelse if (Context.IsOpen)\n{\n    <div class=\"fixed inset-0 z-50\">\n        <div class=\"fixed inset-0 bg-black/80 animate-fade-in\" @onclick=\"HandleBackdropClick\"></div>\n        <div id=\"@_contentId\" class=\"@CssClass\" role=\"dialog\" aria-modal=\"true\" aria-labelledby=\"@Context.TitleId\" aria-describedby=\"@Context.DescriptionId\" @onkeydown=\"HandleKeyDown\" tabindex=\"-1\" @attributes=\"AdditionalAttributes\">\n            @if (ShowDragHandle)\n            {\n                <div class=\"mx-auto mt-4 h-2 w-[100px] rounded-full bg-muted\"></div>\n            }\n            @ChildContent\n        </div>\n    </div>\n}\n\n@inject ComponentInteropService Interop\n\n@code {\n    [CascadingParameter] public Drawer.DrawerContext Context { get; set; } = default!;\n    [CascadingParameter] public OverlayShellMarker? Shell { get; set; }\n    [Parameter] public RenderFragment? ChildContent { get; set; }\n    [Parameter] public DrawerSide Side { get; set; } = DrawerSide.Bottom;\n    [Parameter] public DrawerAnimation Animation { get; set; } = DrawerAnimation.Slide;\n    [Parameter] public bool PreventClose { get; set; }\n    [Parameter] public string? Class { get; set; }\n    [Parameter(CaptureUnmatchedValues = true)] public Dictionary<string, object>? AdditionalAttributes { get; set; }\n\n    private readonly string _contentId = $\"drawer-{Guid.NewGuid():N}\";\n    private bool _wasOpen;\n    // Slide-animation transform trap is fixed via JS interop:\n    // Interop.AttachOverlaySlideEnd registers a native animationend listener\n    // that filters strictly on slide-in-from-* AND on event.target === this\n    // element, then sets inline `transform: none`. See SheetContent for the\n    // full rationale.\n\n    private bool ShowDragHandle => Side is DrawerSide.Top or DrawerSide.Bottom;\n\n    private string PositionClasses => Side switch\n    {\n        DrawerSide.Top => \"inset-x-0 top-0 rounded-b-[10px] max-h-[96vh]\",\n        DrawerSide.Right => \"inset-y-0 right-0 w-3/4 max-w-sm rounded-l-[10px] h-full max-h-screen\",\n        DrawerSide.Bottom => \"inset-x-0 bottom-0 rounded-t-[10px] max-h-[96vh]\",\n        DrawerSide.Left => \"inset-y-0 left-0 w-3/4 max-w-sm rounded-r-[10px] h-full max-h-screen\",\n        _ => \"inset-x-0 bottom-0 rounded-t-[10px] max-h-[96vh]\"\n    };\n\n    private string AnimationClass => Animation switch\n    {\n        DrawerAnimation.None => \"\",\n        DrawerAnimation.Fade => \"animate-fade-in\",\n        DrawerAnimation.Slide => Side switch\n        {\n            DrawerSide.Top => \"animate-slide-in-from-top\",\n            DrawerSide.Right => \"animate-slide-in-from-right\",\n            DrawerSide.Bottom => \"animate-slide-in-from-bottom\",\n            DrawerSide.Left => \"animate-slide-in-from-left\",\n            _ => \"animate-slide-in-from-bottom\"\n        },\n        _ => \"\"\n    };\n\n    private string CssClass =>\n        $\"fixed z-50 mt-24 flex h-auto flex-col bg-background shadow-lg {PositionClasses} {AnimationClass} {Class}\".Trim();\n\n    private string SwipeDirection => Side switch\n    {\n        DrawerSide.Top => \"up\",\n        DrawerSide.Right => \"right\",\n        DrawerSide.Bottom => \"down\",\n        DrawerSide.Left => \"left\",\n        _ => \"down\"\n    };\n\n    protected override async Task OnAfterRenderAsync(bool firstRender)\n    {\n        // Passthrough mode — host DrawerContent owns scroll lock, focus trap, swipe.\n        if (Shell is not null) return;\n\n        if (Context.IsOpen && !_wasOpen)\n        {\n            await Interop.LockScroll();\n            await Interop.SetupFocusTrap(_contentId);\n            // Same animationend cleanup as SheetContent — bypasses Blazor\n            // event roundtrip + filters strictly on slide-in-from-* names.\n            if (Animation == DrawerAnimation.Slide)\n            {\n                await Interop.AttachOverlaySlideEnd(_contentId);\n            }\n            if (!PreventClose)\n            {\n                await Interop.RegisterDrawerSwipe(_contentId, SwipeDirection, Close);\n            }\n            _wasOpen = true;\n        }\n        else if (!Context.IsOpen && _wasOpen)\n        {\n            await Cleanup();\n            _wasOpen = false;\n        }\n    }\n\n    private async Task Close() => await Context.SetOpen.InvokeAsync(false);\n\n    private async Task HandleBackdropClick()\n    {\n        if (!PreventClose) await Close();\n    }\n\n\n    private async Task HandleKeyDown(KeyboardEventArgs e)\n    {\n        if (e.Key == \"Escape\" && !PreventClose) await Close();\n    }\n\n    private async Task Cleanup()\n    {\n        try\n        {\n            await Interop.UnregisterDrawerSwipe(_contentId);\n            await Interop.RemoveFocusTrap(_contentId);\n            await Interop.UnlockScroll();\n        }\n        catch (JSDisconnectedException) { }\n    }\n\n    public async ValueTask DisposeAsync()\n    {\n        if (_wasOpen) await Cleanup();\n    }\n\n    public enum DrawerSide { Top, Right, Bottom, Left }\n    public enum DrawerAnimation { Slide, Fade, None }\n}\n"
    },
    {
      "path": "UI/Drawer/DrawerDescription.razor",
      "content": "@namespace Lumeo\n\n<p id=\"@Context.DescriptionId\" class=\"@CssClass\" @attributes=\"AdditionalAttributes\">\n    @ChildContent\n</p>\n\n@code {\n    [CascadingParameter] public Drawer.DrawerContext Context { get; set; } = default!;\n    [Parameter] public RenderFragment? ChildContent { get; set; }\n    [Parameter] public string? Class { get; set; }\n    [Parameter(CaptureUnmatchedValues = true)] public Dictionary<string, object>? AdditionalAttributes { get; set; }\n\n    private string CssClass => $\"text-sm text-muted-foreground {Class}\".Trim();\n}\n"
    },
    {
      "path": "UI/Drawer/DrawerFooter.razor",
      "content": "@namespace Lumeo\n\n<div class=\"@CssClass\" @attributes=\"AdditionalAttributes\">\n    @ChildContent\n</div>\n\n@code {\n    [Parameter] public RenderFragment? ChildContent { get; set; }\n    [Parameter] public string? Class { get; set; }\n    [Parameter(CaptureUnmatchedValues = true)] public Dictionary<string, object>? AdditionalAttributes { get; set; }\n\n    private string CssClass => $\"mt-auto flex flex-col gap-2 p-4 {Class}\".Trim();\n}\n"
    },
    {
      "path": "UI/Drawer/DrawerHeader.razor",
      "content": "@namespace Lumeo\n\n<div class=\"@CssClass\" @attributes=\"AdditionalAttributes\">\n    @ChildContent\n</div>\n\n@code {\n    [Parameter] public RenderFragment? ChildContent { get; set; }\n    [Parameter] public string? Class { get; set; }\n    [Parameter(CaptureUnmatchedValues = true)] public Dictionary<string, object>? AdditionalAttributes { get; set; }\n\n    private string CssClass => $\"grid gap-1.5 p-4 text-center sm:text-left {Class}\".Trim();\n}\n"
    },
    {
      "path": "UI/Drawer/DrawerTitle.razor",
      "content": "@namespace Lumeo\n\n<h2 id=\"@Context.TitleId\" class=\"@CssClass\" @attributes=\"AdditionalAttributes\">\n    @ChildContent\n</h2>\n\n@code {\n    [CascadingParameter] public Drawer.DrawerContext Context { get; set; } = default!;\n    [Parameter] public RenderFragment? ChildContent { get; set; }\n    [Parameter] public string? Class { get; set; }\n    [Parameter(CaptureUnmatchedValues = true)] public Dictionary<string, object>? AdditionalAttributes { get; set; }\n\n    private string CssClass => $\"text-lg font-semibold leading-none tracking-tight {Class}\".Trim();\n}\n"
    },
    {
      "path": "UI/Drawer/DrawerTrigger.razor",
      "content": "@namespace Lumeo\n\n<div class=\"@CssClass\" role=\"button\" aria-expanded=\"@Context.IsOpen\" @onclick=\"Open\" @attributes=\"AdditionalAttributes\">\n    @ChildContent\n</div>\n\n@code {\n    [CascadingParameter] public Drawer.DrawerContext Context { get; set; } = default!;\n    [Parameter] public RenderFragment? ChildContent { get; set; }\n    [Parameter] public string? Class { get; set; }\n    [Parameter(CaptureUnmatchedValues = true)] public Dictionary<string, object>? AdditionalAttributes { get; set; }\n\n    private string CssClass => $\"inline-flex {Class}\".Trim();\n\n    private async Task Open() => await Context.SetOpen.InvokeAsync(true);\n}\n"
    }
  ],
  "slots": [
    {
      "name": "ChildContent",
      "owner": "Drawer",
      "type": "RenderFragment?",
      "description": null
    },
    {
      "name": "ChildContent",
      "owner": "DrawerClose",
      "type": "RenderFragment?",
      "description": null
    },
    {
      "name": "ChildContent",
      "owner": "DrawerContent",
      "type": "RenderFragment?",
      "description": null
    },
    {
      "name": "ChildContent",
      "owner": "DrawerDescription",
      "type": "RenderFragment?",
      "description": null
    },
    {
      "name": "ChildContent",
      "owner": "DrawerFooter",
      "type": "RenderFragment?",
      "description": null
    },
    {
      "name": "ChildContent",
      "owner": "DrawerHeader",
      "type": "RenderFragment?",
      "description": null
    },
    {
      "name": "ChildContent",
      "owner": "DrawerTitle",
      "type": "RenderFragment?",
      "description": null
    },
    {
      "name": "ChildContent",
      "owner": "DrawerTrigger",
      "type": "RenderFragment?",
      "description": null
    }
  ],
  "serviceDependencies": [
    {
      "service": "ComponentInteropService",
      "namespace": ""
    }
  ],
  "cascadingDependencies": [
    {
      "name": "Context",
      "type": "Drawer.DrawerContext",
      "required": true
    },
    {
      "name": "Shell",
      "type": "OverlayShellMarker?",
      "required": false
    }
  ],
  "relatedComponents": [
    {
      "name": "DrawerClose",
      "reason": "sub-component"
    },
    {
      "name": "DrawerContent",
      "reason": "sub-component"
    },
    {
      "name": "DrawerDescription",
      "reason": "sub-component"
    },
    {
      "name": "DrawerFooter",
      "reason": "sub-component"
    },
    {
      "name": "DrawerHeader",
      "reason": "sub-component"
    },
    {
      "name": "DrawerTitle",
      "reason": "sub-component"
    },
    {
      "name": "DrawerTrigger",
      "reason": "sub-component"
    }
  ],
  "keyboardInteractions": [
    {
      "key": "Escape",
      "action": "HandleKeyDown handles Escape in DrawerContent.razor"
    }
  ],
  "tests": [
    "tests/Lumeo.Docs.Tests/Helpers/DocsTestContext.cs",
    "tests/Lumeo.Tests/Components/Drawer/DrawerTests.cs",
    "tests/Lumeo.Tests/Contract/ComponentContractTests.cs",
    "tests/Lumeo.Tests/Services/Interop/InteropAdapterTests.cs",
    "tests/Lumeo.Tests/Services/StrictInteropTests.cs"
  ],
  "mdSummary": "# Drawer\n\nSlide-up sheet for mobile-first contextual content.\n\n**Package:** `Lumeo` · **Category:** Overlay\n**Docs:** https://lumeo.nativ.sh/components/drawer\n\n## Parameters\n| Owner | Name | Type | Default | Description |\n|---|---|---|---|---|\n| Drawer | ChildContent | `RenderFragment?` | `` |  |\n| Drawer | Open | `bool` | `` |  |\n| Drawer | OpenChanged | `EventCallback<bool>` | `` |  |\n| Drawer | IsOpen | `bool` | `` |  |\n| Drawer | IsOpenChanged | `EventCallback<bool>` | `` |  |\n| DrawerClose | Context | `Drawer.DrawerContext` | `default!` |  |\n| DrawerClose | ChildContent | `RenderFragment?` | `` |  |\n| DrawerClose | Class | `string?` | `` |  |\n| DrawerClose | AdditionalAttributes | `Dictionary<string, object>?` | `` |  |\n| DrawerContent | Context | `Drawer.DrawerContext` | `default!` |  |\n| DrawerContent | Shell | `OverlayShellMarker?` | `` |  |\n| DrawerContent | ChildContent | `RenderFragment?` | `` |  |\n| DrawerContent | Side | `DrawerSide` | `DrawerSide.Bottom` |  |\n| DrawerContent | Animation | `DrawerAnimation` | `DrawerAnimation.Slide` |  |\n| DrawerContent | PreventClose | `bool` | `` |  |\n| DrawerContent | Class | `string?` | `` |  |\n| DrawerContent | AdditionalAttributes | `Dictionary<string, object>?` | `` |  |\n| DrawerDescription | Context | `Drawer.DrawerContext` | `default!` |  |\n| DrawerDescription | ChildContent | `RenderFragment?` | `` |  |\n| DrawerDescription | Class | `string?` | `` |  |\n| DrawerDescription | AdditionalAttributes | `Dictionary<string, object>?` | `` |  |\n| DrawerFooter | ChildContent | `RenderFragment?` | `` |  |\n| DrawerFooter | Class | `string?` | `` |  |\n| DrawerFooter | AdditionalAttributes | `Dictionary<string, object>?` | `` |  |\n| DrawerHeader | ChildContent | `RenderFragment?` | `` |  |\n| DrawerHeader | Class | `string?` | `` |  |\n| DrawerHeader | AdditionalAttributes | `Dictionary<string, object>?` | `` |  |\n| DrawerTitle | Context | `Drawer.DrawerContext` | `default!` |  |\n| DrawerTitle | ChildContent | `RenderFragment?` | `` |  |\n| DrawerTitle | Class | `string?` | `` |  |\n| DrawerTitle | AdditionalAttributes | `Dictionary<string, object>?` | `` |  |\n| DrawerTrigger | Context | `Drawer.DrawerContext` | `default!` |  |\n| DrawerTrigger | ChildContent | `RenderFragment?` | `` |  |\n| DrawerTrigger | Class | `string?` | `` |  |\n| DrawerTrigger | AdditionalAttributes | `Dictionary<string, object>?` | `` |  |\n\n## Slots\n- `ChildContent` (Drawer) — RenderFragment slot\n- `ChildContent` (DrawerClose) — RenderFragment slot\n- `ChildContent` (DrawerContent) — RenderFragment slot\n- `ChildContent` (DrawerDescription) — RenderFragment slot\n- `ChildContent` (DrawerFooter) — RenderFragment slot\n- `ChildContent` (DrawerHeader) — RenderFragment slot\n- `ChildContent` (DrawerTitle) — RenderFragment slot\n- `ChildContent` (DrawerTrigger) — RenderFragment slot\n\n## Events\n- `OpenChanged` (`EventCallback<bool>`)\n- `IsOpenChanged` (`EventCallback<bool>`)\n\n## Sub-components\n- `DrawerClose`, `DrawerContent`, `DrawerDescription`, `DrawerFooter`, `DrawerHeader`, `DrawerTitle`, `DrawerTrigger`\n\n## Cascading values it expects\n- `Context` (`Drawer.DrawerContext`)\n- `Shell` (`OverlayShellMarker?`)\n\n## Services it injects\n- `ComponentInteropService` ()\n\n## Keyboard\n- `Escape` — HandleKeyDown handles Escape in DrawerContent.razor\n\n## Example\n```razor\n<Drawer />\n```\n\n## CSS variables\n`--color-background`, `--color-muted`, `--color-muted-foreground`, `--radius`\n\n## Files\n- `UI/Drawer/Drawer.razor`\n- `UI/Drawer/DrawerClose.razor`\n- `UI/Drawer/DrawerContent.razor`\n- `UI/Drawer/DrawerDescription.razor`\n- `UI/Drawer/DrawerFooter.razor`\n- `UI/Drawer/DrawerHeader.razor`\n- `UI/Drawer/DrawerTitle.razor`\n- `UI/Drawer/DrawerTrigger.razor`\n"
}