{
  "name": "Stepper",
  "category": "Navigation",
  "subcategory": null,
  "description": "Stateful multi-step wizard with navigation, validation gating, and header indicators.",
  "thumbnail": "/preview-cards/stepper.png",
  "hasDocsPage": true,
  "nugetPackage": "Lumeo",
  "files": [
    "UI/Stepper/Stepper.razor",
    "UI/Stepper/StepperStep.razor"
  ],
  "dependencies": [],
  "packageDependencies": [
    "Blazicons.Lucide"
  ],
  "cssVars": [
    "--color-background",
    "--color-border",
    "--color-destructive",
    "--color-foreground",
    "--color-muted",
    "--color-muted-foreground",
    "--color-primary",
    "--color-primary-foreground",
    "--color-ring",
    "--radius"
  ],
  "api": {
    "name": "Stepper",
    "category": "Navigation",
    "subcategory": null,
    "description": "Stateful multi-step wizard with navigation, validation gating, and header indicators.",
    "nugetPackage": "Lumeo",
    "files": [
      "UI/Stepper/Stepper.razor",
      "UI/Stepper/StepperStep.razor"
    ],
    "namespace": "Lumeo",
    "inheritsFrom": null,
    "implements": [],
    "parameters": [
      {
        "name": "ChildContent",
        "type": "RenderFragment?",
        "default": null,
        "description": null,
        "isCascading": false,
        "captureUnmatched": false
      },
      {
        "name": "ActiveStep",
        "type": "int",
        "default": null,
        "description": null,
        "isCascading": false,
        "captureUnmatched": false
      },
      {
        "name": "ActiveStepChanged",
        "type": "EventCallback<int>",
        "default": null,
        "description": null,
        "isCascading": false,
        "captureUnmatched": false
      },
      {
        "name": "Orientation",
        "type": "StepperOrientation",
        "default": "StepperOrientation.Horizontal",
        "description": null,
        "isCascading": false,
        "captureUnmatched": false
      },
      {
        "name": "Linear",
        "type": "bool",
        "default": "true",
        "description": null,
        "isCascading": false,
        "captureUnmatched": false
      },
      {
        "name": "AllowStepClick",
        "type": "bool",
        "default": null,
        "description": null,
        "isCascading": false,
        "captureUnmatched": false
      },
      {
        "name": "OnFinish",
        "type": "EventCallback",
        "default": null,
        "description": null,
        "isCascading": false,
        "captureUnmatched": false
      },
      {
        "name": "NextLabel",
        "type": "string",
        "default": "\"Next\"",
        "description": null,
        "isCascading": false,
        "captureUnmatched": false
      },
      {
        "name": "BackLabel",
        "type": "string",
        "default": "\"Back\"",
        "description": null,
        "isCascading": false,
        "captureUnmatched": false
      },
      {
        "name": "FinishLabel",
        "type": "string",
        "default": "\"Finish\"",
        "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": [
      {
        "name": "ActiveStepChanged",
        "type": "EventCallback<int>",
        "description": null
      },
      {
        "name": "OnFinish",
        "type": "EventCallback",
        "description": null
      }
    ],
    "enums": [
      {
        "name": "StepperOrientation",
        "values": [
          "Horizontal",
          "Vertical"
        ],
        "description": null
      }
    ],
    "records": [
      {
        "name": "StepperContext",
        "signature": "StepperContext(\n        int ActiveStep,\n        EventCallback<int> SetActiveStep,\n        StepperOrientation Orientation,\n        bool Linear,\n        int StepCount,\n        Stepper Parent)",
        "description": null
      }
    ],
    "cssVars": [
      "--color-background",
      "--color-border",
      "--color-destructive",
      "--color-foreground",
      "--color-muted",
      "--color-muted-foreground",
      "--color-primary",
      "--color-primary-foreground",
      "--color-ring",
      "--radius"
    ],
    "examples": [
      {
        "title": "Basic Stepper",
        "code": "<Stepper @bind-ActiveStep=\"_step\" OnFinish=\"HandleFinish\">\n    <StepperStep Title=\"Account Info\" Description=\"Set up your account\">\n        <Input Placeholder=\"Email address\" />\n    </StepperStep>\n    <StepperStep Title=\"Profile\" Description=\"Personalize your profile\">\n        <Input Placeholder=\"Display name\" />\n    </StepperStep>\n    <StepperStep Title=\"Review\">\n        <Lumeo.Text Size=\"sm\" Color=\"muted\">Review your information.</Lumeo.Text>\n    </StepperStep>\n</Stepper>\n\n@code {\n    private int _step;\n    private void HandleFinish() { /* complete */ }\n}"
      },
      {
        "title": "With Optional Step",
        "code": "<Stepper @bind-ActiveStep=\"_step\">\n    <StepperStep Title=\"Basics\">\n        <Input Placeholder=\"Your name\" />\n    </StepperStep>\n    <StepperStep Title=\"Extras\" Optional=\"true\">\n        <Lumeo.Text Size=\"sm\" Color=\"muted\">This step is optional.</Lumeo.Text>\n    </StepperStep>\n    <StepperStep Title=\"Finish\">\n        <Lumeo.Text Size=\"sm\" Color=\"muted\">All done.</Lumeo.Text>\n    </StepperStep>\n</Stepper>"
      },
      {
        "title": "Vertical Orientation",
        "code": "<Stepper @bind-ActiveStep=\"_step\" Orientation=\"Stepper.StepperOrientation.Vertical\">\n    <StepperStep Title=\"Choose plan\" Description=\"Pick a subscription\">\n        <Lumeo.Text Size=\"sm\" Color=\"muted\">Select the plan that fits your needs.</Lumeo.Text>\n    </StepperStep>\n    <StepperStep Title=\"Payment\" Description=\"Enter billing details\">\n        <Input Placeholder=\"Card number\" />\n    </StepperStep>\n    <StepperStep Title=\"Confirm\">\n        <Lumeo.Text Size=\"sm\" Color=\"muted\">Confirm and activate.</Lumeo.Text>\n    </StepperStep>\n</Stepper>"
      },
      {
        "title": "Orientation — interactive",
        "code": "<Segmented @bind-Value=\"_orientationSel\" Options=\"_orientationOptions\" />\n<Stepper @bind-ActiveStep=\"_step\" Orientation=\"@_activeStepperOrientation\">\n    <StepperStep Title=\"Account Info\" Description=\"Set up your account\">\n        <Input Placeholder=\"Email address\" />\n    </StepperStep>\n    <StepperStep Title=\"Profile\" Description=\"Personalize your profile\">\n        <Input Placeholder=\"Display name\" />\n    </StepperStep>\n    <StepperStep Title=\"Review\" Description=\"Confirm your details\">\n        <Lumeo.Text Size=\"sm\" Color=\"muted\">Review your information.</Lumeo.Text>\n    </StepperStep>\n</Stepper>\n\n@code {\n    private string _orientationSel = \"Horizontal\";\n    private Stepper.StepperOrientation _activeStepperOrientation =>\n        Enum.Parse<Stepper.StepperOrientation>(_orientationSel);\n    private List<Segmented.SegmentedOption> _orientationOptions = new()\n    {\n        new() { Label = \"Horizontal\", Value = \"Horizontal\" },\n        new() { Label = \"Vertical\", Value = \"Vertical\" },\n    };\n}"
      }
    ],
    "subComponents": {
      "StepperStep": {
        "componentName": "StepperStep",
        "fileName": "StepperStep.razor",
        "namespace": "Lumeo",
        "inheritsFrom": null,
        "implements": [],
        "parameters": [
          {
            "name": "Context",
            "type": "Stepper.StepperContext?",
            "default": null,
            "description": null,
            "isCascading": true,
            "captureUnmatched": false
          },
          {
            "name": "Title",
            "type": "string",
            "default": "\"\"",
            "description": null,
            "isCascading": false,
            "captureUnmatched": false
          },
          {
            "name": "Description",
            "type": "string?",
            "default": null,
            "description": null,
            "isCascading": false,
            "captureUnmatched": false
          },
          {
            "name": "Optional",
            "type": "bool",
            "default": null,
            "description": null,
            "isCascading": false,
            "captureUnmatched": false
          },
          {
            "name": "Completed",
            "type": "bool",
            "default": null,
            "description": null,
            "isCascading": false,
            "captureUnmatched": false
          },
          {
            "name": "IsValid",
            "type": "Func<bool>?",
            "default": null,
            "description": null,
            "isCascading": false,
            "captureUnmatched": false
          },
          {
            "name": "IconContent",
            "type": "RenderFragment?",
            "default": null,
            "description": null,
            "isCascading": false,
            "captureUnmatched": false
          },
          {
            "name": "ChildContent",
            "type": "RenderFragment?",
            "default": null,
            "description": null,
            "isCascading": false,
            "captureUnmatched": false
          },
          {
            "name": "KeepMounted",
            "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": [],
        "records": [
          {
            "name": "StepRegistration",
            "signature": "StepRegistration(\n        string Title,\n        string? Description,\n        bool Optional,\n        bool Completed,\n        Func<bool>? IsValid,\n        RenderFragment? IconContent,\n        RenderFragment? ChildContent,\n        bool KeepMounted)",
            "description": null
          }
        ],
        "parseFailed": false,
        "parseError": null
      }
    },
    "parseFailed": false,
    "parseError": null
  },
  "$schema": "https://lumeo.nativ.sh/registry-component-schema.json",
  "key": "stepper",
  "docsUrl": "https://lumeo.nativ.sh/components/stepper",
  "sourceUrl": [
    {
      "file": "UI/Stepper/Stepper.razor",
      "url": "https://github.com/Brain2k-0005/Lumeo/tree/master/src/Lumeo/UI/Stepper/Stepper.razor"
    },
    {
      "file": "UI/Stepper/StepperStep.razor",
      "url": "https://github.com/Brain2k-0005/Lumeo/tree/master/src/Lumeo/UI/Stepper/StepperStep.razor"
    }
  ],
  "source": [
    {
      "path": "UI/Stepper/Stepper.razor",
      "content": "@namespace Lumeo\n\n@{\n    _stepIndex = 0;\n    var context = new StepperContext(\n        ActiveStep,\n        EventCallback.Factory.Create<int>(this, SetActiveStep),\n        Orientation,\n        Linear,\n        _stepCount,\n        this);\n}\n\n<div class=\"@CssClass\" @attributes=\"AdditionalAttributes\">\n    <CascadingValue Value=\"context\" IsFixed=\"false\">\n        @* Render ChildContent first (hidden) so StepperStep components register themselves *@\n        <div style=\"display:none\">@ChildContent</div>\n    </CascadingValue>\n\n    @* Header: step indicators *@\n    @{\n        // Resize refs array after ChildContent (hidden) has registered all steps.\n        if (_stepButtonRefs.Length != _steps.Count)\n            _stepButtonRefs = new ElementReference[_steps.Count];\n    }\n    <div role=\"tablist\"\n         aria-orientation=\"@(Orientation == StepperOrientation.Vertical ? \"vertical\" : \"horizontal\")\"\n         class=\"@HeaderCssClass\">\n        @for (int i = 0; i < _steps.Count; i++)\n        {\n            var idx = i;\n            var step = _steps[idx];\n            var isActive = idx == ActiveStep;\n            var isCompleted = step.Completed || idx < ActiveStep;\n            var isError = !step.IsStepValid() && idx < ActiveStep;\n            <button type=\"button\"\n                    role=\"tab\"\n                    aria-selected=\"@isActive.ToString().ToLower()\"\n                    aria-current=\"@(isActive ? \"step\" : null)\"\n                    aria-disabled=\"@(CanClickStep(idx) ? null : \"true\")\"\n                    tabindex=\"@(isActive ? 0 : -1)\"\n                    class=\"@GetStepIndicatorClass(idx, isActive, isCompleted, isError)\"\n                    @ref=\"_stepButtonRefs[idx]\"\n                    @onclick=\"() => HandleStepClick(idx)\"\n                    @onkeydown=\"(e) => HandleStepKeyDown(e, idx)\">\n                @if (step.IconContent is not null && !isCompleted && !isError)\n                {\n                    @step.IconContent\n                }\n                else if (isError)\n                {\n                    <Blazicon Svg=\"Lucide.X\" class=\"h-4 w-4\" />\n                }\n                else if (isCompleted)\n                {\n                    <Blazicon Svg=\"Lucide.Check\" class=\"h-4 w-4\" />\n                }\n                else\n                {\n                    <span class=\"text-sm font-semibold\">@(idx + 1)</span>\n                }\n            </button>\n            @if (Orientation == StepperOrientation.Horizontal)\n            {\n                <div class=\"@GetStepLabelClass(idx, isActive, isCompleted)\">\n                    <span class=\"text-sm font-medium\">@step.Title</span>\n                    @if (!string.IsNullOrEmpty(step.Description))\n                    {\n                        <span class=\"text-xs text-muted-foreground\">@step.Description</span>\n                    }\n                    @if (step.Optional)\n                    {\n                        <span class=\"text-xs text-muted-foreground italic\">Optional</span>\n                    }\n                </div>\n                @if (idx < _steps.Count - 1)\n                {\n                    <div class=\"@GetConnectorClass(idx, isCompleted)\"></div>\n                }\n            }\n        }\n    </div>\n\n    @* Vertical: labels beside indicators *@\n    @if (Orientation == StepperOrientation.Vertical)\n    {\n        <div class=\"flex flex-col gap-0\">\n            @for (int i = 0; i < _steps.Count; i++)\n            {\n                var idx = i;\n                var step = _steps[idx];\n                var isActive = idx == ActiveStep;\n                var isCompleted = step.Completed || idx < ActiveStep;\n                <div class=\"flex flex-row items-start gap-3 @(idx < _steps.Count - 1 ? \"pb-6\" : \"\")\">\n                    <div class=\"flex flex-col items-center\">\n                        <div class=\"h-8 w-8 shrink-0\"></div>\n                        @if (idx < _steps.Count - 1)\n                        {\n                            <div class=\"w-px flex-1 min-h-[24px] @(isCompleted ? \"bg-primary\" : \"bg-border\")\"></div>\n                        }\n                    </div>\n                    <div class=\"pt-1 pb-2\">\n                        <p class=\"@GetVerticalTitleClass(idx, isActive, isCompleted)\">@step.Title</p>\n                        @if (!string.IsNullOrEmpty(step.Description))\n                        {\n                            <p class=\"text-xs text-muted-foreground\">@step.Description</p>\n                        }\n                        @if (step.Optional)\n                        {\n                            <p class=\"text-xs text-muted-foreground italic\">Optional</p>\n                        }\n                    </div>\n                </div>\n            }\n        </div>\n    }\n\n    @* Step body panel *@\n    <div role=\"tabpanel\" class=\"mt-4\">\n        @if (ActiveStep >= 0 && ActiveStep < _steps.Count)\n        {\n            var activeStep = _steps[ActiveStep];\n            @activeStep.ChildContent\n        }\n    </div>\n\n    @* Footer: navigation buttons *@\n    <div class=\"@FooterCssClass\">\n        <button type=\"button\"\n                disabled=\"@(ActiveStep == 0)\"\n                class=\"@GetNavButtonClass(ActiveStep == 0)\"\n                @onclick=\"GoBack\">\n            @BackLabel\n        </button>\n        <div class=\"flex-1\"></div>\n        @if (ActiveStep == _steps.Count - 1)\n        {\n            <button type=\"button\"\n                    disabled=\"@(!CanAdvance())\"\n                    class=\"@GetNavButtonClass(!CanAdvance(), primary: true)\"\n                    @onclick=\"Finish\">\n                @FinishLabel\n            </button>\n        }\n        else\n        {\n            <button type=\"button\"\n                    disabled=\"@(!CanAdvance())\"\n                    class=\"@GetNavButtonClass(!CanAdvance(), primary: true)\"\n                    @onclick=\"GoNext\">\n                @NextLabel\n            </button>\n        }\n    </div>\n</div>\n\n@inject ThemeService Theme\n\n@code {\n    [Parameter] public RenderFragment? ChildContent { get; set; }\n    [Parameter] public int ActiveStep { get; set; }\n    [Parameter] public EventCallback<int> ActiveStepChanged { get; set; }\n    [Parameter] public StepperOrientation Orientation { get; set; } = StepperOrientation.Horizontal;\n    [Parameter] public bool Linear { get; set; } = true;\n    [Parameter] public bool AllowStepClick { get; set; }\n    [Parameter] public EventCallback OnFinish { get; set; }\n    [Parameter] public string NextLabel { get; set; } = \"Next\";\n    [Parameter] public string BackLabel { get; set; } = \"Back\";\n    [Parameter] public string FinishLabel { get; set; } = \"Finish\";\n    [Parameter] public string? Class { get; set; }\n    [Parameter(CaptureUnmatchedValues = true)] public Dictionary<string, object>? AdditionalAttributes { get; set; }\n\n    // Internal step registry — populated by StepperStep on each render pass\n    internal readonly List<StepperStep.StepRegistration> _steps = new();\n    internal int _stepIndex;\n    internal int _stepCount;\n\n    // ElementReferences for each step indicator button — sized in OnParametersSet\n    // so @ref bindings in the render loop always find a valid slot.\n    private ElementReference[] _stepButtonRefs = Array.Empty<ElementReference>();\n\n    internal void RegisterStep(StepperStep.StepRegistration step)\n    {\n        // Steps register themselves during the hidden render pass\n        if (_steps.Count <= _stepIndex)\n            _steps.Add(step);\n        else\n            _steps[_stepIndex] = step;\n        _stepIndex++;\n    }\n\n    protected override void OnParametersSet()\n    {\n        // Reset index so re-render re-registers\n        _stepIndex = 0;\n        _stepCount = _steps.Count;\n\n        // Ensure the refs array is always large enough for the current step count.\n        if (_stepButtonRefs.Length != _steps.Count)\n            _stepButtonRefs = new ElementReference[_steps.Count];\n    }\n\n    private bool CanAdvance()\n    {\n        if (ActiveStep >= _steps.Count) return false;\n        var current = _steps[ActiveStep];\n        return current.IsStepValid();\n    }\n\n    private bool CanClickStep(int idx)\n    {\n        if (!AllowStepClick) return false;\n        if (!Linear) return true;\n        // In linear mode: can only click steps that are completed or the next available\n        return idx <= ActiveStep + (CanAdvance() ? 1 : 0);\n    }\n\n    private async Task HandleStepClick(int idx)\n    {\n        if (!CanClickStep(idx)) return;\n        await SetActiveStep(idx);\n    }\n\n    // Arrow-key navigation between step indicator buttons (WAI-ARIA tab-list pattern).\n    // ArrowUp: move focus to previous button. ArrowDown: next button.\n    // ArrowLeft/Right: previous/next in LTR; swapped in RTL so keys follow visual flow.\n    // Focus only — does not change ActiveStep (use Enter/Space for activation).\n    private async Task HandleStepKeyDown(KeyboardEventArgs e, int idx)\n    {\n        var isRtl = Theme.CurrentDirection == LayoutDirection.Rtl;\n        var (hBack, hForward) = isRtl ? (\"ArrowRight\", \"ArrowLeft\") : (\"ArrowLeft\", \"ArrowRight\");\n\n        int target = e.Key switch\n        {\n            _ when e.Key == hBack   || e.Key == \"ArrowUp\"   => idx - 1,\n            _ when e.Key == hForward || e.Key == \"ArrowDown\" => idx + 1,\n            _ => -1\n        };\n\n        if (target < 0 || target >= _stepButtonRefs.Length) return;\n\n        await _stepButtonRefs[target].FocusAsync();\n    }\n\n    private async Task GoNext()\n    {\n        if (!CanAdvance()) return;\n        if (ActiveStep < _steps.Count - 1)\n            await SetActiveStep(ActiveStep + 1);\n    }\n\n    private async Task GoBack()\n    {\n        if (ActiveStep > 0)\n            await SetActiveStep(ActiveStep - 1);\n    }\n\n    private async Task Finish()\n    {\n        if (!CanAdvance()) return;\n        await OnFinish.InvokeAsync();\n    }\n\n    private async Task SetActiveStep(int value)\n    {\n        ActiveStep = value;\n        await ActiveStepChanged.InvokeAsync(value);\n    }\n\n    private string CssClass => Orientation == StepperOrientation.Vertical\n        ? $\"flex flex-row gap-4 {Class}\".Trim()\n        : $\"flex flex-col gap-0 {Class}\".Trim();\n\n    private string HeaderCssClass => Orientation == StepperOrientation.Horizontal\n        ? \"flex flex-row items-center\"\n        : \"flex flex-col items-center gap-0\";\n\n    private string FooterCssClass => \"flex flex-row items-center gap-2 mt-6 pt-4 border-t border-border/40\";\n\n    private string GetStepIndicatorClass(int idx, bool isActive, bool isCompleted, bool isError)\n    {\n        var baseClasses = \"flex h-8 w-8 shrink-0 items-center justify-center rounded-full transition-colors p-1.5 -m-1.5 sm:p-0 sm:m-0\";\n        var stateClasses = isError\n            ? \"border-2 border-destructive bg-background text-destructive\"\n            : isCompleted\n                ? \"bg-primary text-primary-foreground\"\n                : isActive\n                    ? \"border-2 border-primary bg-background text-primary\"\n                    : \"bg-muted text-muted-foreground\";\n        var cursorClasses = CanClickStep(idx)\n            ? \"cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2\"\n            : \"cursor-default\";\n        return $\"{baseClasses} {stateClasses} {cursorClasses}\";\n    }\n\n    private string GetStepLabelClass(int idx, bool isActive, bool isCompleted) =>\n        \"flex flex-col items-start mx-2\";\n\n    private string GetVerticalTitleClass(int idx, bool isActive, bool isCompleted) =>\n        isActive\n            ? \"text-sm font-semibold text-foreground\"\n            : isCompleted\n                ? \"text-sm font-medium text-foreground\"\n                : \"text-sm text-muted-foreground\";\n\n    private string GetConnectorClass(int idx, bool isCompleted) =>\n        $\"flex-1 h-px mx-2 {(isCompleted ? \"bg-primary\" : \"bg-border/40\")}\";\n\n    private string GetNavButtonClass(bool disabled, bool primary = false)\n    {\n        var baseClasses = \"inline-flex items-center justify-center rounded-md px-4 py-2 text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2\";\n        var variantClasses = primary\n            ? \"bg-primary text-primary-foreground hover:bg-primary/90\"\n            : \"border border-border/40 bg-background text-foreground hover:bg-muted/50\";\n        var disabledClasses = disabled ? \"opacity-50 cursor-not-allowed pointer-events-none\" : \"cursor-pointer\";\n        return $\"{baseClasses} {variantClasses} {disabledClasses}\";\n    }\n\n    public enum StepperOrientation { Horizontal, Vertical }\n\n    public record StepperContext(\n        int ActiveStep,\n        EventCallback<int> SetActiveStep,\n        StepperOrientation Orientation,\n        bool Linear,\n        int StepCount,\n        Stepper Parent);\n}\n"
    },
    {
      "path": "UI/Stepper/StepperStep.razor",
      "content": "@namespace Lumeo\n\n@* StepperStep registers itself into the parent Stepper's step list on each render.\n   The actual rendering is done by Stepper using the registered data. *@\n\n@code {\n    [CascadingParameter] public Stepper.StepperContext? Context { get; set; }\n    [Parameter] public string Title { get; set; } = \"\";\n    [Parameter] public string? Description { get; set; }\n    [Parameter] public bool Optional { get; set; }\n    [Parameter] public bool Completed { get; set; }\n    [Parameter] public Func<bool>? IsValid { get; set; }\n    [Parameter] public RenderFragment? IconContent { get; set; }\n    [Parameter] public RenderFragment? ChildContent { get; set; }\n    [Parameter] public bool KeepMounted { get; set; }\n    [Parameter] public string? Class { get; set; }\n    [Parameter(CaptureUnmatchedValues = true)] public Dictionary<string, object>? AdditionalAttributes { get; set; }\n\n    protected override void OnParametersSet()\n    {\n        Context?.Parent.RegisterStep(new StepRegistration(\n            Title,\n            Description,\n            Optional,\n            Completed,\n            IsValid,\n            IconContent,\n            ChildContent,\n            KeepMounted));\n    }\n\n    public bool IsStepValid() => IsValid?.Invoke() ?? true;\n\n    public record StepRegistration(\n        string Title,\n        string? Description,\n        bool Optional,\n        bool Completed,\n        Func<bool>? IsValid,\n        RenderFragment? IconContent,\n        RenderFragment? ChildContent,\n        bool KeepMounted)\n    {\n        public bool IsStepValid() => IsValid?.Invoke() ?? true;\n    }\n}\n"
    }
  ],
  "slots": [
    {
      "name": "ChildContent",
      "owner": "Stepper",
      "type": "RenderFragment?",
      "description": null
    },
    {
      "name": "IconContent",
      "owner": "StepperStep",
      "type": "RenderFragment?",
      "description": null
    },
    {
      "name": "ChildContent",
      "owner": "StepperStep",
      "type": "RenderFragment?",
      "description": null
    }
  ],
  "serviceDependencies": [
    {
      "service": "ThemeService",
      "namespace": ""
    }
  ],
  "cascadingDependencies": [
    {
      "name": "Context",
      "type": "Stepper.StepperContext?",
      "required": false
    }
  ],
  "relatedComponents": [
    {
      "name": "StepperStep",
      "reason": "sub-component"
    }
  ],
  "keyboardInteractions": [
    {
      "key": "ArrowUp",
      "action": "HandleStepKeyDown handles ArrowUp in Stepper.razor"
    },
    {
      "key": "ArrowDown",
      "action": "HandleStepKeyDown handles ArrowDown in Stepper.razor"
    }
  ],
  "tests": [
    "tests/Lumeo.Tests/Components/Stepper/StepperTests.cs"
  ],
  "mdSummary": "# Stepper\n\nStateful multi-step wizard with navigation, validation gating, and header indicators.\n\n**Package:** `Lumeo` · **Category:** Navigation\n**Docs:** https://lumeo.nativ.sh/components/stepper\n\n## Parameters\n| Owner | Name | Type | Default | Description |\n|---|---|---|---|---|\n| Stepper | ChildContent | `RenderFragment?` | `` |  |\n| Stepper | ActiveStep | `int` | `` |  |\n| Stepper | ActiveStepChanged | `EventCallback<int>` | `` |  |\n| Stepper | Orientation | `StepperOrientation` | `StepperOrientation.Horizontal` |  |\n| Stepper | Linear | `bool` | `true` |  |\n| Stepper | AllowStepClick | `bool` | `` |  |\n| Stepper | OnFinish | `EventCallback` | `` |  |\n| Stepper | NextLabel | `string` | `\"Next\"` |  |\n| Stepper | BackLabel | `string` | `\"Back\"` |  |\n| Stepper | FinishLabel | `string` | `\"Finish\"` |  |\n| Stepper | Class | `string?` | `` |  |\n| Stepper | AdditionalAttributes | `Dictionary<string, object>?` | `` |  |\n| StepperStep | Context | `Stepper.StepperContext?` | `` |  |\n| StepperStep | Title | `string` | `\"\"` |  |\n| StepperStep | Description | `string?` | `` |  |\n| StepperStep | Optional | `bool` | `` |  |\n| StepperStep | Completed | `bool` | `` |  |\n| StepperStep | IsValid | `Func<bool>?` | `` |  |\n| StepperStep | IconContent | `RenderFragment?` | `` |  |\n| StepperStep | ChildContent | `RenderFragment?` | `` |  |\n| StepperStep | KeepMounted | `bool` | `` |  |\n| StepperStep | Class | `string?` | `` |  |\n| StepperStep | AdditionalAttributes | `Dictionary<string, object>?` | `` |  |\n\n## Slots\n- `ChildContent` (Stepper) — RenderFragment slot\n- `IconContent` (StepperStep) — RenderFragment slot\n- `ChildContent` (StepperStep) — RenderFragment slot\n\n## Events\n- `ActiveStepChanged` (`EventCallback<int>`)\n- `OnFinish` (`EventCallback`)\n\n## Sub-components\n- `StepperStep`\n\n## Cascading values it expects\n- `Context` (`Stepper.StepperContext?`)\n\n## Services it injects\n- `ThemeService` ()\n\n## Keyboard\n- `ArrowUp` — HandleStepKeyDown handles ArrowUp in Stepper.razor\n- `ArrowDown` — HandleStepKeyDown handles ArrowDown in Stepper.razor\n\n## Example\n```razor\n<Stepper />\n```\n\n## CSS variables\n`--color-background`, `--color-border`, `--color-destructive`, `--color-foreground`, `--color-muted`, `--color-muted-foreground`, `--color-primary`, `--color-primary-foreground`, `--color-ring`, `--radius`\n\n## Files\n- `UI/Stepper/Stepper.razor`\n- `UI/Stepper/StepperStep.razor`\n"
}