{
  "name": "Sparkline",
  "category": "Data Display",
  "subcategory": "Status & Indicators",
  "description": "Inline SVG trend chart primitive — line, area, or bars for tables and KPI strips.",
  "thumbnail": "/preview-cards/sparkline.png",
  "hasDocsPage": true,
  "nugetPackage": "Lumeo",
  "files": [
    "UI/Sparkline/Sparkline.razor"
  ],
  "dependencies": [],
  "packageDependencies": [],
  "cssVars": [
    "--color-foreground"
  ],
  "api": {
    "name": "Sparkline",
    "category": "Data Display",
    "subcategory": "Status & Indicators",
    "description": "Inline SVG trend chart primitive — line, area, or bars for tables and KPI strips.",
    "nugetPackage": "Lumeo",
    "files": [
      "UI/Sparkline/Sparkline.razor"
    ],
    "namespace": "Lumeo",
    "inheritsFrom": null,
    "implements": [],
    "parameters": [
      {
        "name": "Values",
        "type": "IEnumerable<double>?",
        "default": null,
        "description": null,
        "isCascading": false,
        "captureUnmatched": false
      },
      {
        "name": "Height",
        "type": "int",
        "default": "32",
        "description": null,
        "isCascading": false,
        "captureUnmatched": false
      },
      {
        "name": "Color",
        "type": "string?",
        "default": null,
        "description": null,
        "isCascading": false,
        "captureUnmatched": false
      },
      {
        "name": "Type",
        "type": "SparkType",
        "default": "SparkType.Line",
        "description": null,
        "isCascading": false,
        "captureUnmatched": false
      },
      {
        "name": "ShowArea",
        "type": "bool",
        "default": null,
        "description": null,
        "isCascading": false,
        "captureUnmatched": false
      },
      {
        "name": "ShowLast",
        "type": "bool",
        "default": null,
        "description": null,
        "isCascading": false,
        "captureUnmatched": false
      },
      {
        "name": "StrokeWidth",
        "type": "double",
        "default": "1.5",
        "description": null,
        "isCascading": false,
        "captureUnmatched": false
      },
      {
        "name": "AriaLabel",
        "type": "string?",
        "default": "\"Trend\"",
        "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": "SparkType",
        "values": [
          "Line",
          "Area",
          "Bars"
        ],
        "description": null
      }
    ],
    "records": [],
    "cssVars": [
      "--color-foreground"
    ],
    "examples": [],
    "subComponents": {},
    "parseFailed": false,
    "parseError": null
  },
  "$schema": "https://lumeo.nativ.sh/registry-component-schema.json",
  "key": "sparkline",
  "docsUrl": "https://lumeo.nativ.sh/components/sparkline",
  "sourceUrl": [
    {
      "file": "UI/Sparkline/Sparkline.razor",
      "url": "https://github.com/Brain2k-0005/Lumeo/tree/master/src/Lumeo/UI/Sparkline/Sparkline.razor"
    }
  ],
  "source": [
    {
      "path": "UI/Sparkline/Sparkline.razor",
      "content": "@namespace Lumeo\n\n<svg viewBox=\"0 0 100 @Height\"\n     preserveAspectRatio=\"none\"\n     class=\"@CssClass\"\n     style=\"@InlineStyle\"\n     aria-label=\"@AriaLabel\"\n     role=\"img\"\n     @attributes=\"AdditionalAttributes\">\n    @((MarkupString)_shapesHtml)\n</svg>\n\n@code {\n    public enum SparkType { Line, Area, Bars }\n\n    [Parameter] public IEnumerable<double>? Values { get; set; }\n    [Parameter] public int Height { get; set; } = 32;\n    [Parameter] public string? Color { get; set; }\n    [Parameter] public SparkType Type { get; set; } = SparkType.Line;\n    [Parameter] public bool ShowArea { get; set; }\n    [Parameter] public bool ShowLast { get; set; }\n    [Parameter] public double StrokeWidth { get; set; } = 1.5;\n    [Parameter] public string? AriaLabel { get; set; } = \"Trend\";\n    [Parameter] public string? Class { get; set; }\n    [Parameter(CaptureUnmatchedValues = true)] public Dictionary<string, object>? AdditionalAttributes { get; set; }\n\n    private string _shapesHtml = string.Empty;\n\n    private string CssClass => $\"inline-block w-full align-middle {Class}\".Trim();\n\n    private string InlineStyle\n    {\n        get\n        {\n            var style = $\"height: {Height}px;\";\n            if (!string.IsNullOrEmpty(Color)) style += $\" color: {Color};\";\n            return style;\n        }\n    }\n\n    protected override void OnParametersSet()\n    {\n        _shapesHtml = BuildShapes();\n    }\n\n    private string BuildShapes()\n    {\n        var list = Values?.ToList();\n        if (list is null || list.Count == 0)\n        {\n            // Baseline rect so the component has a visible footprint.\n            return $\"<rect x=\\\"0\\\" y=\\\"{F(Height / 2.0 - 0.5)}\\\" width=\\\"100\\\" height=\\\"1\\\" fill=\\\"var(--color-muted-foreground, currentColor)\\\" opacity=\\\"0.35\\\" />\";\n        }\n\n        var color = string.IsNullOrEmpty(Color) ? \"var(--color-primary, currentColor)\" : Color;\n        var min = list.Min();\n        var max = list.Max();\n        var range = max - min;\n        const double pad = 2.0;\n        var usable = Height - (pad * 2);\n\n        double ScaleY(double v)\n        {\n            if (range == 0) return Height / 2.0;\n            var norm = (v - min) / range;\n            return Height - pad - (norm * usable);\n        }\n\n        var sb = new System.Text.StringBuilder();\n\n        if (Type == SparkType.Bars)\n        {\n            var n = list.Count;\n            var slot = 100.0 / n;\n            var barWidth = Math.Max(0.5, slot - 1);\n            var zeroY = Height - pad;\n            for (int i = 0; i < n; i++)\n            {\n                var x = i * slot + (slot - barWidth) / 2.0;\n                var y = ScaleY(list[i]);\n                var h = Math.Max(0.5, zeroY - y);\n                sb.Append($\"<rect x=\\\"{F(x)}\\\" y=\\\"{F(y)}\\\" width=\\\"{F(barWidth)}\\\" height=\\\"{F(h)}\\\" fill=\\\"{color}\\\" />\");\n            }\n        }\n        else\n        {\n            var n = list.Count;\n            var pts = new System.Text.StringBuilder();\n            for (int i = 0; i < n; i++)\n            {\n                var x = n == 1 ? 50.0 : (double)i / (n - 1) * 100.0;\n                var y = ScaleY(list[i]);\n                if (i > 0) pts.Append(' ');\n                pts.Append($\"{F(x)},{F(y)}\");\n            }\n            var pointsStr = pts.ToString();\n\n            if (Type == SparkType.Area || ShowArea)\n            {\n                var lastX = n == 1 ? 50.0 : 100.0;\n                var firstX = n == 1 ? 50.0 : 0.0;\n                var polyPoints = $\"{F(firstX)},{F(Height)} {pointsStr} {F(lastX)},{F(Height)}\";\n                sb.Append($\"<polygon points=\\\"{polyPoints}\\\" fill=\\\"{color}\\\" fill-opacity=\\\"0.2\\\" stroke=\\\"none\\\" />\");\n                sb.Append($\"<polyline points=\\\"{pointsStr}\\\" fill=\\\"none\\\" stroke=\\\"{color}\\\" stroke-width=\\\"{F(StrokeWidth)}\\\" stroke-linecap=\\\"round\\\" stroke-linejoin=\\\"round\\\" vector-effect=\\\"non-scaling-stroke\\\" />\");\n            }\n            else\n            {\n                sb.Append($\"<polyline points=\\\"{pointsStr}\\\" fill=\\\"none\\\" stroke=\\\"{color}\\\" stroke-width=\\\"{F(StrokeWidth)}\\\" stroke-linecap=\\\"round\\\" stroke-linejoin=\\\"round\\\" vector-effect=\\\"non-scaling-stroke\\\" />\");\n            }\n        }\n\n        if (ShowLast && list.Count > 0)\n        {\n            double lx, ly;\n            if (Type == SparkType.Bars)\n            {\n                var n = list.Count;\n                var slot = 100.0 / n;\n                lx = (n - 1) * slot + slot / 2.0;\n                ly = ScaleY(list[^1]);\n            }\n            else\n            {\n                var n = list.Count;\n                lx = n == 1 ? 50.0 : 100.0;\n                ly = ScaleY(list[^1]);\n            }\n            var r = (Type == SparkType.Area || ShowArea) ? 2.75 : 2.25;\n            sb.Append($\"<circle cx=\\\"{F(lx)}\\\" cy=\\\"{F(ly)}\\\" r=\\\"{F(r)}\\\" fill=\\\"{color}\\\" />\");\n        }\n\n        return sb.ToString();\n    }\n\n    private static string F(double v) => v.ToString(\"0.##\", System.Globalization.CultureInfo.InvariantCulture);\n}\n"
    }
  ],
  "slots": [],
  "serviceDependencies": [],
  "cascadingDependencies": [],
  "relatedComponents": [],
  "keyboardInteractions": [],
  "tests": [
    "tests/Lumeo.Tests/Components/Sparkline/SparklineTests.cs"
  ],
  "mdSummary": "# Sparkline\n\nInline SVG trend chart primitive — line, area, or bars for tables and KPI strips.\n\n**Package:** `Lumeo` · **Category:** Data Display/Status & Indicators\n**Docs:** https://lumeo.nativ.sh/components/sparkline\n\n## Parameters\n| Owner | Name | Type | Default | Description |\n|---|---|---|---|---|\n| Sparkline | Values | `IEnumerable<double>?` | `` |  |\n| Sparkline | Height | `int` | `32` |  |\n| Sparkline | Color | `string?` | `` |  |\n| Sparkline | Type | `SparkType` | `SparkType.Line` |  |\n| Sparkline | ShowArea | `bool` | `` |  |\n| Sparkline | ShowLast | `bool` | `` |  |\n| Sparkline | StrokeWidth | `double` | `1.5` |  |\n| Sparkline | AriaLabel | `string?` | `\"Trend\"` |  |\n| Sparkline | Class | `string?` | `` |  |\n| Sparkline | 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- (none)\n\n## Keyboard\n—\n\n## Example\n```razor\n<Sparkline />\n```\n\n## CSS variables\n`--color-foreground`\n\n## Files\n- `UI/Sparkline/Sparkline.razor`\n"
}