{
  "name": "Button",
  "category": "Forms",
  "subcategory": "Buttons & Actions",
  "description": "Versatile button with variants, sizes, icons, and loading states.",
  "thumbnail": "/preview-cards/button.png",
  "hasDocsPage": true,
  "nugetPackage": "Lumeo",
  "files": [
    "UI/Button/Button.razor"
  ],
  "dependencies": [
    "spinner"
  ],
  "packageDependencies": [],
  "cssVars": [
    "--color-accent",
    "--color-accent-foreground",
    "--color-background",
    "--color-destructive",
    "--color-destructive-foreground",
    "--color-input",
    "--color-primary",
    "--color-primary-foreground",
    "--color-ring",
    "--color-secondary",
    "--color-secondary-foreground",
    "--radius"
  ],
  "api": {
    "name": "Button",
    "category": "Forms",
    "subcategory": "Buttons & Actions",
    "description": "Versatile button with variants, sizes, icons, and loading states.",
    "nugetPackage": "Lumeo",
    "files": [
      "UI/Button/Button.razor"
    ],
    "namespace": "Lumeo",
    "inheritsFrom": null,
    "implements": [],
    "parameters": [
      {
        "name": "ChildContent",
        "type": "RenderFragment?",
        "default": null,
        "description": null,
        "isCascading": false,
        "captureUnmatched": false
      },
      {
        "name": "LeftIcon",
        "type": "RenderFragment?",
        "default": null,
        "description": null,
        "isCascading": false,
        "captureUnmatched": false
      },
      {
        "name": "RightIcon",
        "type": "RenderFragment?",
        "default": null,
        "description": null,
        "isCascading": false,
        "captureUnmatched": false
      },
      {
        "name": "Variant",
        "type": "ButtonVariant",
        "default": "ButtonVariant.Default",
        "description": null,
        "isCascading": false,
        "captureUnmatched": false
      },
      {
        "name": "Size",
        "type": "ButtonSize",
        "default": "ButtonSize.Default",
        "description": null,
        "isCascading": false,
        "captureUnmatched": false
      },
      {
        "name": "FullWidth",
        "type": "bool",
        "default": null,
        "description": null,
        "isCascading": false,
        "captureUnmatched": false
      },
      {
        "name": "Class",
        "type": "string?",
        "default": null,
        "description": null,
        "isCascading": false,
        "captureUnmatched": false
      },
      {
        "name": "OnClick",
        "type": "EventCallback<Microsoft.AspNetCore.Components.Web.MouseEventArgs>",
        "default": null,
        "description": null,
        "isCascading": false,
        "captureUnmatched": false
      },
      {
        "name": "Disabled",
        "type": "bool",
        "default": null,
        "description": null,
        "isCascading": false,
        "captureUnmatched": false
      },
      {
        "name": "IsLoading",
        "type": "bool",
        "default": null,
        "description": null,
        "isCascading": false,
        "captureUnmatched": false
      },
      {
        "name": "LoadingText",
        "type": "string?",
        "default": null,
        "description": null,
        "isCascading": false,
        "captureUnmatched": false
      },
      {
        "name": "Type",
        "type": "ButtonType",
        "default": "ButtonType.Button",
        "description": "HTML button type. Defaults to Button — explicitly NOT submit. The HTML spec says &lt;button&gt; inside &lt;form&gt; defaults to type=\"submit\", which would submit the form on every click. Lumeo defaults to a regular button so Buttons don't silently submit EditForm; opt in via Type=\"Submit\".",
        "isCascading": false,
        "captureUnmatched": false
      },
      {
        "name": "StopPropagation",
        "type": "bool",
        "default": null,
        "description": "Stop click propagation to ancestors. Use this instead of the Razor directive @@onclick:stopPropagation on a Lumeo component — that directive creates an onclick parameter that case-insensitively collides with the OnClick parameter, producing a compile error. The directive only works natively on HTML elements; this parameter is the equivalent for the &lt;button&gt; element underneath.",
        "isCascading": false,
        "captureUnmatched": false
      },
      {
        "name": "PreventDefault",
        "type": "bool",
        "default": null,
        "description": "Prevent the default click action on the underlying &lt;button&gt; element. Same rationale as StopPropagation — Razor's @@onclick:preventDefault directive collides case-insensitively with the OnClick parameter on components.",
        "isCascading": false,
        "captureUnmatched": false
      },
      {
        "name": "PressEffect",
        "type": "ButtonPressEffect",
        "default": "ButtonPressEffect.None",
        "description": "Visual feedback when the button is pressed down. Default is None (no press animation — original behaviour).",
        "isCascading": false,
        "captureUnmatched": false
      },
      {
        "name": "AdditionalAttributes",
        "type": "Dictionary<string, object>?",
        "default": null,
        "description": null,
        "isCascading": false,
        "captureUnmatched": true
      }
    ],
    "events": [
      {
        "name": "OnClick",
        "type": "EventCallback<Microsoft.AspNetCore.Components.Web.MouseEventArgs>",
        "description": null
      }
    ],
    "enums": [
      {
        "name": "ButtonVariant",
        "values": [
          "Default",
          "Destructive",
          "Outline",
          "Secondary",
          "Ghost",
          "Link"
        ],
        "description": null
      },
      {
        "name": "ButtonSize",
        "values": [
          "Default",
          "Sm",
          "Lg",
          "Icon"
        ],
        "description": null
      },
      {
        "name": "ButtonType",
        "values": [
          "Button",
          "Submit",
          "Reset"
        ],
        "description": null
      },
      {
        "name": "ButtonPressEffect",
        "values": [
          "None",
          "Scale",
          "Brightness",
          "Ripple"
        ],
        "description": "Visual press feedback style for Button."
      }
    ],
    "records": [],
    "cssVars": [
      "--color-accent",
      "--color-accent-foreground",
      "--color-background",
      "--color-destructive",
      "--color-destructive-foreground",
      "--color-input",
      "--color-primary",
      "--color-primary-foreground",
      "--color-ring",
      "--color-secondary",
      "--color-secondary-foreground",
      "--radius"
    ],
    "examples": [
      {
        "title": "Variants",
        "code": "<Button>Default</Button>\n<Button Variant=\"Button.ButtonVariant.Secondary\">Secondary</Button>\n<Button Variant=\"Button.ButtonVariant.Destructive\">Destructive</Button>\n<Button Variant=\"Button.ButtonVariant.Outline\">Outline</Button>\n<Button Variant=\"Button.ButtonVariant.Ghost\">Ghost</Button>\n<Button Variant=\"Button.ButtonVariant.Link\">Link</Button>"
      },
      {
        "title": "Sizes",
        "code": "<Button Size=\"Button.ButtonSize.Sm\">Small</Button>\n<Button>Default</Button>\n<Button Size=\"Button.ButtonSize.Lg\">Large</Button>\n<Button Size=\"Button.ButtonSize.Icon\">\n    <Blazicon Svg=\"Lucide.ChevronRight\" class=\"h-4 w-4\" />\n</Button>"
      },
      {
        "title": "With Icon",
        "code": "<Button>\n    <Blazicon Svg=\"Lucide.Mail\" class=\"h-4 w-4\" />\n    Login with Email\n</Button>\n<Button Variant=\"Button.ButtonVariant.Secondary\">\n    <Blazicon Svg=\"Lucide.Loader2\" class=\"h-4 w-4 animate-spin\" />\n    Please wait\n</Button>"
      },
      {
        "title": "Disabled",
        "code": "<Button disabled>Disabled</Button>\n<Button Variant=\"Button.ButtonVariant.Outline\" disabled>Disabled</Button>"
      }
    ],
    "subComponents": {},
    "parseFailed": false,
    "parseError": null
  },
  "$schema": "https://lumeo.nativ.sh/registry-component-schema.json",
  "key": "button",
  "docsUrl": "https://lumeo.nativ.sh/components/button",
  "sourceUrl": [
    {
      "file": "UI/Button/Button.razor",
      "url": "https://github.com/Brain2k-0005/Lumeo/tree/master/src/Lumeo/UI/Button/Button.razor"
    }
  ],
  "source": [
    {
      "path": "UI/Button/Button.razor",
      "content": "@namespace Lumeo\n@inject Lumeo.Services.IComponentInteropService Interop\n\n<button @ref=\"_el\" type=\"@TypeAttr\" class=\"@CssClass\" disabled=\"@(IsLoading || Disabled)\" @attributes=\"AdditionalAttributes\" @onclick=\"OnClick\" @onclick:stopPropagation=\"StopPropagation\" @onclick:preventDefault=\"PreventDefault\">\n    @if (IsLoading)\n    {\n        <Spinner Class=\"h-4 w-4\" />\n        @if (LoadingText != null)\n        {\n            <span>@LoadingText</span>\n        }\n        else\n        {\n            @ChildContent\n        }\n        @if (RightIcon != null)\n        {\n            @RightIcon\n        }\n    }\n    else\n    {\n        @if (LeftIcon != null)\n        {\n            @LeftIcon\n        }\n        @ChildContent\n        @if (RightIcon != null)\n        {\n            @RightIcon\n        }\n    }\n</button>\n\n@code {\n    [Parameter] public RenderFragment? ChildContent { get; set; }\n    [Parameter] public RenderFragment? LeftIcon { get; set; }\n    [Parameter] public RenderFragment? RightIcon { get; set; }\n    [Parameter] public ButtonVariant Variant { get; set; } = ButtonVariant.Default;\n    [Parameter] public ButtonSize Size { get; set; } = ButtonSize.Default;\n    [Parameter] public bool FullWidth { get; set; }\n    [Parameter] public string? Class { get; set; }\n    [Parameter] public EventCallback<Microsoft.AspNetCore.Components.Web.MouseEventArgs> OnClick { get; set; }\n    [Parameter] public bool Disabled { get; set; }\n    [Parameter] public bool IsLoading { get; set; }\n    [Parameter] public string? LoadingText { get; set; }\n\n    /// <summary>HTML button type. Defaults to <see cref=\"ButtonType.Button\"/>\n    /// — explicitly NOT submit. The HTML spec says &lt;button&gt; inside\n    /// &lt;form&gt; defaults to <c>type=\"submit\"</c>, which would submit the\n    /// form on every click. Lumeo defaults to a regular button so Buttons\n    /// don't silently submit EditForm; opt in via <c>Type=\"Submit\"</c>.</summary>\n    [Parameter] public ButtonType Type { get; set; } = ButtonType.Button;\n\n    /// <summary>Stop click propagation to ancestors. Use this instead of\n    /// the Razor directive <c>@@onclick:stopPropagation</c> on a Lumeo\n    /// component — that directive creates an <c>onclick</c> parameter\n    /// that case-insensitively collides with the <c>OnClick</c>\n    /// parameter, producing a compile error. The directive only works\n    /// natively on HTML elements; this parameter is the equivalent for\n    /// the &lt;button&gt; element underneath.</summary>\n    [Parameter] public bool StopPropagation { get; set; }\n\n    /// <summary>Prevent the default click action on the underlying\n    /// &lt;button&gt; element. Same rationale as <see cref=\"StopPropagation\"/>\n    /// — Razor's <c>@@onclick:preventDefault</c> directive collides\n    /// case-insensitively with the <c>OnClick</c> parameter on\n    /// components.</summary>\n    [Parameter] public bool PreventDefault { get; set; }\n\n    /// <summary>\n    /// Visual feedback when the button is pressed down. Default is <see cref=\"ButtonPressEffect.None\"/>\n    /// (no press animation — original behaviour).\n    /// </summary>\n    [Parameter] public ButtonPressEffect PressEffect { get; set; } = ButtonPressEffect.None;\n\n    [Parameter(CaptureUnmatchedValues = true)] public Dictionary<string, object>? AdditionalAttributes { get; set; }\n\n    private Microsoft.AspNetCore.Components.ElementReference _el;\n\n    private string CssClass => string.Join(\" \", new[] { VariantClasses, SizeClasses, BaseClasses, PressEffectClass, \"cursor-pointer disabled:cursor-not-allowed\", IsLoading ? \"pointer-events-none opacity-70\" : null, FullWidth ? \"w-full\" : null, Class }.Where(s => !string.IsNullOrWhiteSpace(s)));\n\n    private const string BaseClasses = \"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-[1.5px] focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50\";\n\n    private string? PressEffectClass => PressEffect switch\n    {\n        ButtonPressEffect.Scale => \"lumeo-press-scale\",\n        ButtonPressEffect.Brightness => \"lumeo-press-brightness\",\n        ButtonPressEffect.Ripple => \"lumeo-press-ripple\",\n        _ => null\n    };\n\n    private string VariantClasses => Variant switch\n    {\n        ButtonVariant.Default => \"bg-primary text-primary-foreground shadow hover:bg-primary/90\",\n        ButtonVariant.Destructive => \"bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90\",\n        ButtonVariant.Outline => \"border border-input bg-background hover:bg-accent hover:text-accent-foreground\",\n        ButtonVariant.Secondary => \"bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80\",\n        ButtonVariant.Ghost => \"hover:bg-accent hover:text-accent-foreground\",\n        ButtonVariant.Link => \"text-primary underline-offset-4 hover:underline\",\n        _ => \"\"\n    };\n\n    private string SizeClasses => Size switch\n    {\n        ButtonSize.Default => \"h-9 px-4 py-2\",\n        ButtonSize.Sm => \"h-8 rounded-md px-3 text-xs\",\n        ButtonSize.Lg => \"h-10 rounded-md px-8\",\n        ButtonSize.Icon => \"h-9 w-9\",\n        _ => \"\"\n    };\n\n    protected override async Task OnAfterRenderAsync(bool firstRender)\n    {\n        if (firstRender && PressEffect == ButtonPressEffect.Ripple)\n        {\n            try\n            {\n                await Interop.RippleAttachAsync(_el);\n            }\n            catch (Microsoft.JSInterop.JSDisconnectedException) { }\n        }\n    }\n\n    public enum ButtonVariant { Default, Destructive, Outline, Secondary, Ghost, Link }\n    public enum ButtonSize { Default, Sm, Lg, Icon }\n    public enum ButtonType { Button, Submit, Reset }\n\n    private string TypeAttr => Type switch\n    {\n        ButtonType.Submit => \"submit\",\n        ButtonType.Reset => \"reset\",\n        _ => \"button\",\n    };\n\n    /// <summary>Visual press feedback style for <see cref=\"Button\"/>.</summary>\n    public enum ButtonPressEffect\n    {\n        /// <summary>No press animation (default).</summary>\n        None,\n        /// <summary>Button slightly scales down (~97%) while pressed.</summary>\n        Scale,\n        /// <summary>Button darkens/brightens slightly while pressed.</summary>\n        Brightness,\n        /// <summary>Click ripples outward from the cursor point (JS-interop, uses CSS mask).</summary>\n        Ripple\n    }\n}\n"
    }
  ],
  "slots": [
    {
      "name": "ChildContent",
      "owner": "Button",
      "type": "RenderFragment?",
      "description": null
    },
    {
      "name": "LeftIcon",
      "owner": "Button",
      "type": "RenderFragment?",
      "description": null
    },
    {
      "name": "RightIcon",
      "owner": "Button",
      "type": "RenderFragment?",
      "description": null
    }
  ],
  "serviceDependencies": [
    {
      "service": "IComponentInteropService",
      "namespace": "Lumeo.Services"
    }
  ],
  "cascadingDependencies": [],
  "relatedComponents": [
    {
      "name": "Spinner",
      "reason": "used internally"
    }
  ],
  "keyboardInteractions": [],
  "tests": [
    "tests/Lumeo.Docs.Tests/Catalog/CatalogCardTests.cs",
    "tests/Lumeo.Docs.Tests/Services/NavConfigServiceTests.cs",
    "tests/Lumeo.Tests.E2E/Smokes/CatalogPageRendersTests.cs",
    "tests/Lumeo.Tests.E2E/Smokes/SearchPaletteTests.cs",
    "tests/Lumeo.Tests/Components/BottomNav/BottomNavItemCursorTests.cs",
    "tests/Lumeo.Tests/Components/Button/ButtonPressEffectTests.cs",
    "tests/Lumeo.Tests/Components/Button/ButtonTests.cs",
    "tests/Lumeo.Tests/Components/Card/CardInteractiveTests.cs",
    "tests/Lumeo.Tests/Components/DropdownButton/DropdownButtonTests.cs",
    "tests/Lumeo.Tests/Components/FileUpload/FileUploadTests.cs",
    "tests/Lumeo.Tests/Components/ShimmerButton/ShimmerButtonPressEffectTests.cs",
    "tests/Lumeo.Tests/Components/ShimmerButton/ShimmerButtonTests.cs",
    "tests/Lumeo.Tests/Components/SplitButton/SplitButtonTests.cs",
    "tests/Lumeo.Tests/Helpers/TestContextExtensions.cs"
  ],
  "mdSummary": "# Button\n\nVersatile button with variants, sizes, icons, and loading states.\n\n**Package:** `Lumeo` · **Category:** Forms/Buttons & Actions\n**Docs:** https://lumeo.nativ.sh/components/button\n\n## Parameters\n| Owner | Name | Type | Default | Description |\n|---|---|---|---|---|\n| Button | ChildContent | `RenderFragment?` | `` |  |\n| Button | LeftIcon | `RenderFragment?` | `` |  |\n| Button | RightIcon | `RenderFragment?` | `` |  |\n| Button | Variant | `ButtonVariant` | `ButtonVariant.Default` |  |\n| Button | Size | `ButtonSize` | `ButtonSize.Default` |  |\n| Button | FullWidth | `bool` | `` |  |\n| Button | Class | `string?` | `` |  |\n| Button | OnClick | `EventCallback<Microsoft.AspNetCore.Components.Web.MouseEventArgs>` | `` |  |\n| Button | Disabled | `bool` | `` |  |\n| Button | IsLoading | `bool` | `` |  |\n| Button | LoadingText | `string?` | `` |  |\n| Button | Type | `ButtonType` | `ButtonType.Button` | HTML button type. Defaults to Button — explicitly NOT submit. The HTML spec says &lt;button&gt; inside &lt;form&gt; defaults to type=\"submit\", which would submit the form on every click. Lumeo defaults to a regular button so Buttons don't silently submit EditForm; opt in via Type=\"Submit\". |\n| Button | StopPropagation | `bool` | `` | Stop click propagation to ancestors. Use this instead of the Razor directive @@onclick:stopPropagation on a Lumeo component — that directive creates an onclick parameter that case-insensitively collides with the OnClick parameter, producing a compile error. The directive only works natively on HTML elements; this parameter is the equivalent for the &lt;button&gt; element underneath. |\n| Button | PreventDefault | `bool` | `` | Prevent the default click action on the underlying &lt;button&gt; element. Same rationale as StopPropagation — Razor's @@onclick:preventDefault directive collides case-insensitively with the OnClick parameter on components. |\n| Button | PressEffect | `ButtonPressEffect` | `ButtonPressEffect.None` | Visual feedback when the button is pressed down. Default is None (no press animation — original behaviour). |\n| Button | AdditionalAttributes | `Dictionary<string, object>?` | `` |  |\n\n## Slots\n- `ChildContent` (Button) — RenderFragment slot\n- `LeftIcon` (Button) — RenderFragment slot\n- `RightIcon` (Button) — RenderFragment slot\n\n## Events\n- `OnClick` (`EventCallback<Microsoft.AspNetCore.Components.Web.MouseEventArgs>`)\n\n## Sub-components\n- (none)\n\n## Cascading values it expects\n- (none)\n\n## Services it injects\n- `IComponentInteropService` (Lumeo.Services)\n\n## Keyboard\n—\n\n## Example\n```razor\n<Button />\n```\n\n## CSS variables\n`--color-accent`, `--color-accent-foreground`, `--color-background`, `--color-destructive`, `--color-destructive-foreground`, `--color-input`, `--color-primary`, `--color-primary-foreground`, `--color-ring`, `--color-secondary`, `--color-secondary-foreground`, `--radius`\n\n## Files\n- `UI/Button/Button.razor`\n"
}