{
  "name": "Tooltip",
  "category": "Overlay",
  "subcategory": null,
  "description": "Hover/focus tooltip with arrow and configurable placement.",
  "thumbnail": "/preview-cards/tooltip.png",
  "hasDocsPage": true,
  "nugetPackage": "Lumeo",
  "files": [
    "UI/Tooltip/Tooltip.razor",
    "UI/Tooltip/TooltipContent.razor",
    "UI/Tooltip/TooltipTrigger.razor"
  ],
  "dependencies": [],
  "packageDependencies": [],
  "cssVars": [
    "--color-primary",
    "--color-primary-foreground",
    "--radius"
  ],
  "api": {
    "name": "Tooltip",
    "category": "Overlay",
    "subcategory": null,
    "description": "Hover/focus tooltip with arrow and configurable placement.",
    "nugetPackage": "Lumeo",
    "files": [
      "UI/Tooltip/Tooltip.razor",
      "UI/Tooltip/TooltipContent.razor",
      "UI/Tooltip/TooltipTrigger.razor"
    ],
    "namespace": "Lumeo",
    "inheritsFrom": null,
    "implements": [
      "IAsyncDisposable"
    ],
    "parameters": [
      {
        "name": "ChildContent",
        "type": "RenderFragment?",
        "default": null,
        "description": null,
        "isCascading": false,
        "captureUnmatched": false
      },
      {
        "name": "ShowDelay",
        "type": "int",
        "default": "200",
        "description": null,
        "isCascading": false,
        "captureUnmatched": false
      },
      {
        "name": "HideDelay",
        "type": "int",
        "default": "0",
        "description": null,
        "isCascading": false,
        "captureUnmatched": false
      },
      {
        "name": "AdditionalAttributes",
        "type": "Dictionary<string, object>?",
        "default": null,
        "description": null,
        "isCascading": false,
        "captureUnmatched": true
      }
    ],
    "events": [],
    "enums": [],
    "records": [
      {
        "name": "TooltipContext",
        "signature": "TooltipContext(bool IsOpen)",
        "description": null
      }
    ],
    "cssVars": [
      "--color-primary",
      "--color-primary-foreground",
      "--radius"
    ],
    "examples": [
      {
        "title": "Default",
        "code": "<Tooltip>\n    <TooltipTrigger>\n        <Button Variant=\"Button.ButtonVariant.Outline\">Hover me</Button>\n    </TooltipTrigger>\n    <TooltipContent>\n        <p>Add to library</p>\n    </TooltipContent>\n</Tooltip>"
      },
      {
        "title": "Side Variations",
        "code": "<Tooltip>\n    <TooltipTrigger>\n        <Button Variant=\"Button.ButtonVariant.Outline\">Top</Button>\n    </TooltipTrigger>\n    <TooltipContent Side=\"TooltipContent.TooltipSide.Top\">\n        <p>Tooltip on top</p>\n    </TooltipContent>\n</Tooltip>\n\n<Tooltip>\n    <TooltipTrigger>\n        <Button Variant=\"Button.ButtonVariant.Outline\">Bottom</Button>\n    </TooltipTrigger>\n    <TooltipContent Side=\"TooltipContent.TooltipSide.Bottom\">\n        <p>Tooltip on bottom</p>\n    </TooltipContent>\n</Tooltip>"
      },
      {
        "title": "With Icons",
        "code": "<Tooltip>\n    <TooltipTrigger>\n        <Button Variant=\"Button.ButtonVariant.Outline\" Size=\"Button.ButtonSize.Icon\">\n            <Blazicon Svg=\"Lucide.Bold\" class=\"h-4 w-4\" />\n        </Button>\n    </TooltipTrigger>\n    <TooltipContent>\n        <p>Bold</p>\n    </TooltipContent>\n</Tooltip>\n\n<Tooltip>\n    <TooltipTrigger>\n        <Button Variant=\"Button.ButtonVariant.Outline\" Size=\"Button.ButtonSize.Icon\">\n            <Blazicon Svg=\"Lucide.Italic\" class=\"h-4 w-4\" />\n        </Button>\n    </TooltipTrigger>\n    <TooltipContent>\n        <p>Italic</p>\n    </TooltipContent>\n</Tooltip>"
      },
      {
        "title": "Placement",
        "code": "<Tooltip>\n    <TooltipTrigger><Button Variant=\"Button.ButtonVariant.Outline\">Top</Button></TooltipTrigger>\n    <TooltipContent Side=\"TooltipContent.TooltipSide.Top\">Top tooltip</TooltipContent>\n</Tooltip>\n<Tooltip>\n    <TooltipTrigger><Button Variant=\"Button.ButtonVariant.Outline\">Bottom</Button></TooltipTrigger>\n    <TooltipContent Side=\"TooltipContent.TooltipSide.Bottom\">Bottom tooltip</TooltipContent>\n</Tooltip>\n<Tooltip>\n    <TooltipTrigger><Button Variant=\"Button.ButtonVariant.Outline\">Left</Button></TooltipTrigger>\n    <TooltipContent Side=\"TooltipContent.TooltipSide.Left\">Left tooltip</TooltipContent>\n</Tooltip>\n<Tooltip>\n    <TooltipTrigger><Button Variant=\"Button.ButtonVariant.Outline\">Right</Button></TooltipTrigger>\n    <TooltipContent Side=\"TooltipContent.TooltipSide.Right\">Right tooltip</TooltipContent>\n</Tooltip>"
      }
    ],
    "subComponents": {
      "TooltipContent": {
        "componentName": "TooltipContent",
        "fileName": "TooltipContent.razor",
        "namespace": "Lumeo",
        "inheritsFrom": null,
        "implements": [],
        "parameters": [
          {
            "name": "Context",
            "type": "Tooltip.TooltipContext?",
            "default": null,
            "description": null,
            "isCascading": true,
            "captureUnmatched": false
          },
          {
            "name": "ChildContent",
            "type": "RenderFragment?",
            "default": null,
            "description": null,
            "isCascading": false,
            "captureUnmatched": false
          },
          {
            "name": "Side",
            "type": "TooltipSide",
            "default": "TooltipSide.Top",
            "description": null,
            "isCascading": false,
            "captureUnmatched": false
          },
          {
            "name": "ShowArrow",
            "type": "bool",
            "default": "true",
            "description": null,
            "isCascading": false,
            "captureUnmatched": false
          },
          {
            "name": "Offset",
            "type": "int",
            "default": "8",
            "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": "TooltipSide",
            "values": [
              "Top",
              "Bottom",
              "Left",
              "Right"
            ],
            "description": null
          }
        ],
        "records": [],
        "parseFailed": false,
        "parseError": null
      },
      "TooltipTrigger": {
        "componentName": "TooltipTrigger",
        "fileName": "TooltipTrigger.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
      }
    },
    "parseFailed": false,
    "parseError": null
  },
  "$schema": "https://lumeo.nativ.sh/registry-component-schema.json",
  "key": "tooltip",
  "docsUrl": "https://lumeo.nativ.sh/components/tooltip",
  "sourceUrl": [
    {
      "file": "UI/Tooltip/Tooltip.razor",
      "url": "https://github.com/Brain2k-0005/Lumeo/tree/master/src/Lumeo/UI/Tooltip/Tooltip.razor"
    },
    {
      "file": "UI/Tooltip/TooltipContent.razor",
      "url": "https://github.com/Brain2k-0005/Lumeo/tree/master/src/Lumeo/UI/Tooltip/TooltipContent.razor"
    },
    {
      "file": "UI/Tooltip/TooltipTrigger.razor",
      "url": "https://github.com/Brain2k-0005/Lumeo/tree/master/src/Lumeo/UI/Tooltip/TooltipTrigger.razor"
    }
  ],
  "source": [
    {
      "path": "UI/Tooltip/Tooltip.razor",
      "content": "@namespace Lumeo\n@implements IAsyncDisposable\n@inject Lumeo.Services.ComponentInteropService Interop\n\n@{\n    var context = new TooltipContext(_isOpen);\n}\n\n<div id=\"@_wrapperId\" class=\"relative inline-flex\"\n     @onmouseenter=\"HandleMouseEnter\"\n     @onmouseleave=\"HandleMouseLeave\"\n     @onclick=\"HandleTap\"\n     @attributes=\"AdditionalAttributes\">\n    <CascadingValue Value=\"context\" IsFixed=\"false\">\n        @ChildContent\n    </CascadingValue>\n</div>\n\n@code {\n    [Parameter] public RenderFragment? ChildContent { get; set; }\n    [Parameter] public int ShowDelay { get; set; } = 200;\n    [Parameter] public int HideDelay { get; set; } = 0;\n    [Parameter(CaptureUnmatchedValues = true)] public Dictionary<string, object>? AdditionalAttributes { get; set; }\n\n    private readonly string _wrapperId = $\"tooltip-wrapper-{Guid.NewGuid():N}\";\n    private bool _hovered;\n    // rc.44 — on touch devices a tap \"pins\" the tooltip open until the next\n    // tap elsewhere (registerClickOutside also now listens for touchstart, so\n    // dismissal works equally on mobile).\n    private bool _pinned;\n    private bool _clickOutsideRegistered;\n    private readonly DelayedDispatch _dispatch = new();\n\n    private bool _isOpen => _hovered || _pinned;\n\n    private void HandleMouseEnter()\n    {\n        _dispatch.Cancel();\n        if (ShowDelay <= 0)\n        {\n            _hovered = true;\n            StateHasChanged();\n        }\n        else\n        {\n            _dispatch.Schedule(ShowDelay, () => InvokeAsync(() =>\n            {\n                _hovered = true;\n                StateHasChanged();\n                return Task.CompletedTask;\n            }));\n        }\n    }\n\n    private void HandleMouseLeave()\n    {\n        _dispatch.Cancel();\n        if (HideDelay <= 0)\n        {\n            _hovered = false;\n            StateHasChanged();\n        }\n        else\n        {\n            _dispatch.Schedule(HideDelay, () => InvokeAsync(() =>\n            {\n                _hovered = false;\n                StateHasChanged();\n                return Task.CompletedTask;\n            }));\n        }\n    }\n\n    // Tap toggles the pinned state. The first tap on a touch device fires\n    // both `mouseenter` (browser-emulated) and `click` — that's fine: pin\n    // simply sticks open. A second tap on the trigger unpins.\n    private async Task HandleTap()\n    {\n        _pinned = !_pinned;\n        if (_pinned && !_clickOutsideRegistered)\n        {\n            await Interop.RegisterClickOutside(_wrapperId, null, OnClickOutside);\n            _clickOutsideRegistered = true;\n        }\n        StateHasChanged();\n    }\n\n    private Task OnClickOutside()\n    {\n        if (_pinned)\n        {\n            _pinned = false;\n            _hovered = false;\n            StateHasChanged();\n        }\n        return Task.CompletedTask;\n    }\n\n    public async ValueTask DisposeAsync()\n    {\n        _dispatch.Dispose();\n        if (_clickOutsideRegistered)\n        {\n            try { await Interop.UnregisterClickOutside(_wrapperId); }\n            catch (Microsoft.JSInterop.JSDisconnectedException) { }\n            _clickOutsideRegistered = false;\n        }\n    }\n\n    public record TooltipContext(bool IsOpen);\n}\n"
    },
    {
      "path": "UI/Tooltip/TooltipContent.razor",
      "content": "@namespace Lumeo\n\n<div role=\"tooltip\" class=\"@CssClass\" @attributes=\"AdditionalAttributes\">\n    @ChildContent\n    @if (ShowArrow)\n    {\n        <div class=\"@ArrowClasses\"></div>\n    }\n</div>\n\n@code {\n    [CascadingParameter] public Tooltip.TooltipContext? Context { get; set; }\n\n    [Parameter] public RenderFragment? ChildContent { get; set; }\n    [Parameter] public TooltipSide Side { get; set; } = TooltipSide.Top;\n    [Parameter] public bool ShowArrow { get; set; } = true;\n    [Parameter] public int Offset { get; set; } = 8;\n    [Parameter] public string? Class { get; set; }\n    [Parameter(CaptureUnmatchedValues = true)] public Dictionary<string, object>? AdditionalAttributes { get; set; }\n\n    private bool IsOpen => Context?.IsOpen ?? false;\n\n    private string CssClass => string.Join(\" \", new[] { \"absolute z-50 overflow-visible rounded-md bg-primary px-3 py-1.5 text-xs text-primary-foreground\", AnimationClasses, SideClasses, Class }.Where(s => !string.IsNullOrWhiteSpace(s)));\n\n    private string AnimationClasses => IsOpen\n        ? \"opacity-100 visible animate-fade-in\"\n        : \"opacity-0 invisible\";\n\n    private string SideClasses => Side switch\n    {\n        TooltipSide.Top => $\"bottom-full left-1/2 -translate-x-1/2 mb-{MarginValue}\",\n        TooltipSide.Bottom => $\"top-full left-1/2 -translate-x-1/2 mt-{MarginValue}\",\n        TooltipSide.Left => $\"right-full top-1/2 -translate-y-1/2 mr-{MarginValue}\",\n        TooltipSide.Right => $\"left-full top-1/2 -translate-y-1/2 ml-{MarginValue}\",\n        _ => $\"bottom-full left-1/2 -translate-x-1/2 mb-{MarginValue}\"\n    };\n\n    private string MarginValue => Offset switch\n    {\n        <= 4 => \"1\",\n        <= 8 => \"2\",\n        <= 12 => \"3\",\n        _ => \"4\"\n    };\n\n    // Rotated square — same visual as Popover/HoverCard but no border (tooltip is a solid primary surface).\n    private string ArrowClasses => Side switch\n    {\n        TooltipSide.Top => \"absolute left-1/2 top-full -translate-x-1/2 -translate-y-1/2 rotate-45 h-2 w-2 bg-primary\",\n        TooltipSide.Bottom => \"absolute left-1/2 bottom-full -translate-x-1/2 translate-y-1/2 rotate-45 h-2 w-2 bg-primary\",\n        TooltipSide.Left => \"absolute top-1/2 left-full -translate-y-1/2 -translate-x-1/2 rotate-45 h-2 w-2 bg-primary\",\n        TooltipSide.Right => \"absolute top-1/2 right-full -translate-y-1/2 translate-x-1/2 rotate-45 h-2 w-2 bg-primary\",\n        _ => \"absolute left-1/2 top-full -translate-x-1/2 -translate-y-1/2 rotate-45 h-2 w-2 bg-primary\"\n    };\n\n    public enum TooltipSide { Top, Bottom, Left, Right }\n}\n"
    },
    {
      "path": "UI/Tooltip/TooltipTrigger.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 => $\"inline-flex {Class}\".Trim();\n}\n"
    }
  ],
  "slots": [
    {
      "name": "ChildContent",
      "owner": "Tooltip",
      "type": "RenderFragment?",
      "description": null
    },
    {
      "name": "ChildContent",
      "owner": "TooltipContent",
      "type": "RenderFragment?",
      "description": null
    },
    {
      "name": "ChildContent",
      "owner": "TooltipTrigger",
      "type": "RenderFragment?",
      "description": null
    }
  ],
  "serviceDependencies": [
    {
      "service": "ComponentInteropService",
      "namespace": "Lumeo.Services"
    }
  ],
  "cascadingDependencies": [
    {
      "name": "Context",
      "type": "Tooltip.TooltipContext?",
      "required": false
    }
  ],
  "relatedComponents": [
    {
      "name": "TooltipContent",
      "reason": "sub-component"
    },
    {
      "name": "TooltipTrigger",
      "reason": "sub-component"
    }
  ],
  "keyboardInteractions": [],
  "tests": [
    "tests/Lumeo.Tests.E2E/Smokes/TooltipHoverTests.cs",
    "tests/Lumeo.Tests/Components/Tooltip/TooltipTests.cs"
  ],
  "mdSummary": "# Tooltip\n\nHover/focus tooltip with arrow and configurable placement.\n\n**Package:** `Lumeo` · **Category:** Overlay\n**Docs:** https://lumeo.nativ.sh/components/tooltip\n\n## Parameters\n| Owner | Name | Type | Default | Description |\n|---|---|---|---|---|\n| Tooltip | ChildContent | `RenderFragment?` | `` |  |\n| Tooltip | ShowDelay | `int` | `200` |  |\n| Tooltip | HideDelay | `int` | `0` |  |\n| Tooltip | AdditionalAttributes | `Dictionary<string, object>?` | `` |  |\n| TooltipContent | Context | `Tooltip.TooltipContext?` | `` |  |\n| TooltipContent | ChildContent | `RenderFragment?` | `` |  |\n| TooltipContent | Side | `TooltipSide` | `TooltipSide.Top` |  |\n| TooltipContent | ShowArrow | `bool` | `true` |  |\n| TooltipContent | Offset | `int` | `8` |  |\n| TooltipContent | Class | `string?` | `` |  |\n| TooltipContent | AdditionalAttributes | `Dictionary<string, object>?` | `` |  |\n| TooltipTrigger | ChildContent | `RenderFragment?` | `` |  |\n| TooltipTrigger | Class | `string?` | `` |  |\n| TooltipTrigger | AdditionalAttributes | `Dictionary<string, object>?` | `` |  |\n\n## Slots\n- `ChildContent` (Tooltip) — RenderFragment slot\n- `ChildContent` (TooltipContent) — RenderFragment slot\n- `ChildContent` (TooltipTrigger) — RenderFragment slot\n\n## Events\n- (none)\n\n## Sub-components\n- `TooltipContent`, `TooltipTrigger`\n\n## Cascading values it expects\n- `Context` (`Tooltip.TooltipContext?`)\n\n## Services it injects\n- `ComponentInteropService` (Lumeo.Services)\n\n## Keyboard\n—\n\n## Example\n```razor\n<Tooltip />\n```\n\n## CSS variables\n`--color-primary`, `--color-primary-foreground`, `--radius`\n\n## Files\n- `UI/Tooltip/Tooltip.razor`\n- `UI/Tooltip/TooltipContent.razor`\n- `UI/Tooltip/TooltipTrigger.razor`\n"
}