{
  "name": "SpeedDial",
  "category": "Navigation",
  "subcategory": null,
  "description": "Floating action button that fans out sub-actions.",
  "thumbnail": "/preview-cards/speed-dial.png",
  "hasDocsPage": true,
  "nugetPackage": "Lumeo",
  "files": [
    "UI/SpeedDial/SpeedDial.razor"
  ],
  "dependencies": [],
  "packageDependencies": [
    "Blazicons.Lucide"
  ],
  "cssVars": [
    "--color-border",
    "--color-popover",
    "--color-popover-foreground",
    "--color-primary",
    "--color-primary-foreground",
    "--color-ring",
    "--color-secondary",
    "--color-secondary-foreground",
    "--radius"
  ],
  "api": {
    "name": "SpeedDial",
    "category": "Navigation",
    "subcategory": null,
    "description": "Floating action button that fans out sub-actions.",
    "nugetPackage": "Lumeo",
    "files": [
      "UI/SpeedDial/SpeedDial.razor"
    ],
    "namespace": "Lumeo",
    "inheritsFrom": null,
    "implements": [
      "IAsyncDisposable"
    ],
    "parameters": [
      {
        "name": "Items",
        "type": "List<SpeedDialItem>",
        "default": "new()",
        "description": null,
        "isCascading": false,
        "captureUnmatched": false
      },
      {
        "name": "Icon",
        "type": "string?",
        "default": null,
        "description": null,
        "isCascading": false,
        "captureUnmatched": false
      },
      {
        "name": "Position",
        "type": "SpeedDialPosition",
        "default": "SpeedDialPosition.BottomRight",
        "description": null,
        "isCascading": false,
        "captureUnmatched": false
      },
      {
        "name": "Direction",
        "type": "SpeedDialDirection",
        "default": "SpeedDialDirection.Up",
        "description": null,
        "isCascading": false,
        "captureUnmatched": false
      },
      {
        "name": "Variant",
        "type": "string",
        "default": "\"Default\"",
        "description": null,
        "isCascading": false,
        "captureUnmatched": false
      },
      {
        "name": "Disabled",
        "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": "SpeedDialPosition",
        "values": [
          "BottomRight",
          "BottomLeft",
          "TopRight",
          "TopLeft"
        ],
        "description": null
      },
      {
        "name": "SpeedDialDirection",
        "values": [
          "Up",
          "Down",
          "Left",
          "Right"
        ],
        "description": null
      }
    ],
    "records": [],
    "cssVars": [
      "--color-border",
      "--color-popover",
      "--color-popover-foreground",
      "--color-primary",
      "--color-primary-foreground",
      "--color-ring",
      "--color-secondary",
      "--color-secondary-foreground",
      "--radius"
    ],
    "examples": [
      {
        "title": "Basic Speed Dial (Bottom Right)",
        "code": "<SpeedDial Items=\"@_actions\" />\n\n@code {\n    private List<SpeedDial.SpeedDialItem> _actions = new()\n    {\n        new() { Label = \"New Document\", Icon = \"\uD83D\uDCC4\" },\n        new() { Label = \"Upload File\", Icon = \"\uD83D\uDCC1\" },\n        new() { Label = \"Add Reminder\", Icon = \"\uD83D\uDD14\" },\n    };\n}"
      },
      {
        "title": "Bottom Left Position",
        "code": "<SpeedDial Items=\"@_actions\" Position=\"SpeedDial.SpeedDialPosition.BottomLeft\" />"
      },
      {
        "title": "Direction: Left",
        "code": "<SpeedDial Items=\"@_actions\"\n         Position=\"SpeedDial.SpeedDialPosition.TopRight\"\n         Direction=\"SpeedDial.SpeedDialDirection.Left\" />"
      }
    ],
    "subComponents": {},
    "parseFailed": false,
    "parseError": null
  },
  "$schema": "https://lumeo.nativ.sh/registry-component-schema.json",
  "key": "speed-dial",
  "docsUrl": "https://lumeo.nativ.sh/components/speed-dial",
  "sourceUrl": [
    {
      "file": "UI/SpeedDial/SpeedDial.razor",
      "url": "https://github.com/Brain2k-0005/Lumeo/tree/master/src/Lumeo/UI/SpeedDial/SpeedDial.razor"
    }
  ],
  "source": [
    {
      "path": "UI/SpeedDial/SpeedDial.razor",
      "content": "@namespace Lumeo\n@implements IAsyncDisposable\n\n<div id=\"@_wrapperId\" class=\"@PositionClass @Class\" @attributes=\"AdditionalAttributes\">\n    @if (_isOpen)\n    {\n        <div id=\"@_contentId\" class=\"@ItemsContainerClass\">\n            @foreach (var item in Items)\n            {\n                <div class=\"@(string.Join(\" \", new[] { \"flex\", Direction == SpeedDialDirection.Left || Direction == SpeedDialDirection.Right ? \"flex-col\" : null, \"items-center gap-2\", Direction == SpeedDialDirection.Right || Direction == SpeedDialDirection.Down ? \"flex-row-reverse\" : null }.Where(s => !string.IsNullOrWhiteSpace(s))))\">\n                    <span class=\"whitespace-nowrap rounded-md bg-popover border border-border px-2 py-1 text-xs text-popover-foreground shadow-md\">\n                        @item.Label\n                    </span>\n                    <button type=\"button\"\n                            class=\"flex h-10 w-10 cursor-pointer items-center justify-center rounded-full bg-secondary text-secondary-foreground shadow-md transition-all hover:bg-secondary/80 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:opacity-50 disabled:cursor-not-allowed\"\n                            @onclick=\"() => HandleItemClick(item)\"\n                            disabled=\"@item.Disabled\"\n                            title=\"@item.Label\">\n                        @if (!string.IsNullOrEmpty(item.Icon))\n                        {\n                            <span class=\"text-sm\">@item.Icon</span>\n                        }\n                    </button>\n                </div>\n            }\n        </div>\n    }\n\n    <button type=\"button\"\n            class=\"@TriggerClass\"\n            @onclick=\"ToggleOpen\"\n            aria-expanded=\"@_isOpen\"\n            aria-label=\"Actions\"\n            disabled=\"@Disabled\">\n        @{ var plusClass = string.Join(\" \", new[] { \"h-6 w-6 transition-transform\", _isOpen ? \"rotate-45\" : null }.Where(s => !string.IsNullOrWhiteSpace(s))); }\n        <Blazicon Svg=\"Lucide.Plus\" class=\"@plusClass\" />\n    </button>\n</div>\n\n@inject ComponentInteropService Interop\n\n@code {\n    [Parameter] public List<SpeedDialItem> Items { get; set; } = new();\n    [Parameter] public string? Icon { get; set; }\n    [Parameter] public SpeedDialPosition Position { get; set; } = SpeedDialPosition.BottomRight;\n    [Parameter] public SpeedDialDirection Direction { get; set; } = SpeedDialDirection.Up;\n    [Parameter] public string Variant { get; set; } = \"Default\";\n    [Parameter] public bool Disabled { 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 _wrapperId = $\"speeddial-{Guid.NewGuid():N}\";\n    private readonly string _contentId = $\"speeddial-content-{Guid.NewGuid():N}\";\n    private bool _isOpen;\n    private bool _registered;\n\n    private string PositionClass => Position switch\n    {\n        SpeedDialPosition.BottomLeft => \"fixed bottom-6 left-6 z-50 flex flex-col-reverse items-start\",\n        SpeedDialPosition.TopRight => \"fixed top-6 right-6 z-50 flex flex-col items-end\",\n        SpeedDialPosition.TopLeft => \"fixed top-6 left-6 z-50 flex flex-col items-start\",\n        _ => \"fixed bottom-6 right-6 z-50 flex flex-col-reverse items-end\"\n    };\n\n    private string ItemsContainerClass\n    {\n        get\n        {\n            var directionClass = Direction switch\n            {\n                SpeedDialDirection.Down => \"flex flex-col mt-2\",\n                SpeedDialDirection.Left => \"flex flex-row-reverse mr-2\",\n                SpeedDialDirection.Right => \"flex flex-row ml-2\",\n                _ => \"flex flex-col-reverse mb-2\"\n            };\n            return $\"{directionClass} gap-2 animate-fade-in\";\n        }\n    }\n\n    private string TriggerClass =>\n        Disabled\n            ? \"flex h-14 w-14 cursor-not-allowed items-center justify-center rounded-full bg-primary text-primary-foreground shadow-lg opacity-50 pointer-events-none\"\n            : \"flex h-14 w-14 cursor-pointer items-center justify-center rounded-full bg-primary text-primary-foreground shadow-lg transition-all hover:bg-primary/90 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2\";\n\n    private async Task ToggleOpen()\n    {\n        if (Disabled) return;\n        if (_isOpen)\n            await Close();\n        else\n            await Open();\n    }\n\n    private async Task Open()\n    {\n        _isOpen = true;\n        StateHasChanged();\n        await Task.Yield();\n        await Interop.RegisterClickOutside(_wrapperId, null, async () =>\n        {\n            await Close();\n            await InvokeAsync(StateHasChanged);\n        });\n        _registered = true;\n    }\n\n    private async Task Close()\n    {\n        _isOpen = false;\n        if (_registered)\n        {\n            try { await Interop.UnregisterClickOutside(_wrapperId); }\n            catch (JSDisconnectedException) { }\n            _registered = false;\n        }\n    }\n\n    private async Task HandleItemClick(SpeedDialItem item)\n    {\n        if (Disabled || item.Disabled) return;\n        await item.OnClick.InvokeAsync();\n        await Close();\n    }\n\n    public async ValueTask DisposeAsync()\n    {\n        if (_registered)\n        {\n            try { await Interop.UnregisterClickOutside(_wrapperId); }\n            catch (JSDisconnectedException) { }\n        }\n    }\n\n    public class SpeedDialItem\n    {\n        public string Label { get; set; } = \"\";\n        public string? Icon { get; set; }\n        public EventCallback OnClick { get; set; }\n        public bool Disabled { get; set; }\n    }\n\n    public enum SpeedDialPosition { BottomRight, BottomLeft, TopRight, TopLeft }\n    public enum SpeedDialDirection { Up, Down, Left, Right }\n}\n"
    }
  ],
  "slots": [],
  "serviceDependencies": [
    {
      "service": "ComponentInteropService",
      "namespace": ""
    }
  ],
  "cascadingDependencies": [],
  "relatedComponents": [],
  "keyboardInteractions": [],
  "tests": [
    "tests/Lumeo.Tests/Components/SpeedDial/SpeedDialTests.cs"
  ],
  "mdSummary": "# SpeedDial\n\nFloating action button that fans out sub-actions.\n\n**Package:** `Lumeo` · **Category:** Navigation\n**Docs:** https://lumeo.nativ.sh/components/speed-dial\n\n## Parameters\n| Owner | Name | Type | Default | Description |\n|---|---|---|---|---|\n| SpeedDial | Items | `List<SpeedDialItem>` | `new()` |  |\n| SpeedDial | Icon | `string?` | `` |  |\n| SpeedDial | Position | `SpeedDialPosition` | `SpeedDialPosition.BottomRight` |  |\n| SpeedDial | Direction | `SpeedDialDirection` | `SpeedDialDirection.Up` |  |\n| SpeedDial | Variant | `string` | `\"Default\"` |  |\n| SpeedDial | Disabled | `bool` | `` |  |\n| SpeedDial | Class | `string?` | `` |  |\n| SpeedDial | AdditionalAttributes | `Dictionary<string, object>?` | `` |  |\n\n## Slots\n- (none)\n\n## Events\n- (none)\n\n## Sub-components\n- (none)\n\n## Cascading values it expects\n- (none)\n\n## Services it injects\n- `ComponentInteropService` ()\n\n## Keyboard\n—\n\n## Example\n```razor\n<SpeedDial />\n```\n\n## CSS variables\n`--color-border`, `--color-popover`, `--color-popover-foreground`, `--color-primary`, `--color-primary-foreground`, `--color-ring`, `--color-secondary`, `--color-secondary-foreground`, `--radius`\n\n## Files\n- `UI/SpeedDial/SpeedDial.razor`\n"
}