{
  "name": "Gantt",
  "category": "Data Display",
  "subcategory": "Lists & Trees",
  "description": "Gantt component.",
  "thumbnail": "/preview-cards/gantt.png",
  "hasDocsPage": true,
  "nugetPackage": "Lumeo.Gantt",
  "files": [
    "UI/Gantt/Gantt.razor",
    "UI/Gantt/GanttTypes.cs"
  ],
  "dependencies": [
    "toggle-group"
  ],
  "packageDependencies": [],
  "cssVars": [
    "--color-border",
    "--color-card",
    "--color-destructive",
    "--radius"
  ],
  "api": {
    "name": "Gantt",
    "category": "Data Display",
    "subcategory": "Lists & Trees",
    "description": "Gantt component.",
    "nugetPackage": "Lumeo.Gantt",
    "files": [
      "UI/Gantt/Gantt.razor",
      "UI/Gantt/GanttTypes.cs"
    ],
    "namespace": "Lumeo",
    "inheritsFrom": null,
    "implements": [
      "IAsyncDisposable"
    ],
    "parameters": [
      {
        "name": "Tasks",
        "type": "IEnumerable<GanttTask>?",
        "default": null,
        "description": null,
        "isCascading": false,
        "captureUnmatched": false
      },
      {
        "name": "TasksChanged",
        "type": "EventCallback<IEnumerable<GanttTask>>",
        "default": null,
        "description": null,
        "isCascading": false,
        "captureUnmatched": false
      },
      {
        "name": "ViewMode",
        "type": "GanttViewMode",
        "default": "GanttViewMode.Day",
        "description": null,
        "isCascading": false,
        "captureUnmatched": false
      },
      {
        "name": "OnTaskClick",
        "type": "EventCallback<GanttTask>",
        "default": null,
        "description": null,
        "isCascading": false,
        "captureUnmatched": false
      },
      {
        "name": "OnDateChange",
        "type": "EventCallback<GanttTask>",
        "default": null,
        "description": null,
        "isCascading": false,
        "captureUnmatched": false
      },
      {
        "name": "OnProgressChange",
        "type": "EventCallback<GanttTask>",
        "default": null,
        "description": null,
        "isCascading": false,
        "captureUnmatched": false
      },
      {
        "name": "Height",
        "type": "string",
        "default": "\"500px\"",
        "description": null,
        "isCascading": false,
        "captureUnmatched": false
      },
      {
        "name": "Readonly",
        "type": "bool",
        "default": null,
        "description": null,
        "isCascading": false,
        "captureUnmatched": false
      },
      {
        "name": "TodayHighlight",
        "type": "bool",
        "default": "true",
        "description": "Highlight today with a vertical line and dot marker. Default true.",
        "isCascading": false,
        "captureUnmatched": false
      },
      {
        "name": "BarHeight",
        "type": "int?",
        "default": null,
        "description": "Override the pixel height of each task bar (default 22).",
        "isCascading": false,
        "captureUnmatched": false
      },
      {
        "name": "ColumnWidth",
        "type": "int?",
        "default": null,
        "description": "Override the pixel width of each date column for the current view mode.",
        "isCascading": false,
        "captureUnmatched": false
      },
      {
        "name": "BarColor",
        "type": "Func<GanttTask, string?>?",
        "default": null,
        "description": "Per-task bar colour override. Return a CSS colour string (hex, rgb, or a CSS variable reference like \"var(--color-destructive)\") or null to use the primary theme colour.",
        "isCascading": false,
        "captureUnmatched": false
      },
      {
        "name": "GroupBy",
        "type": "Func<GanttTask, string>?",
        "default": null,
        "description": "Optional grouping function. When set, tasks are sorted by group label and a visual section-header row is injected before the first task in each group.",
        "isCascading": false,
        "captureUnmatched": false
      },
      {
        "name": "TrailingContent",
        "type": "RenderFragment?",
        "default": null,
        "description": null,
        "isCascading": false,
        "captureUnmatched": false
      },
      {
        "name": "OnInitError",
        "type": "EventCallback<string>",
        "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": [
      {
        "name": "TasksChanged",
        "type": "EventCallback<IEnumerable<GanttTask>>",
        "description": null
      },
      {
        "name": "OnTaskClick",
        "type": "EventCallback<GanttTask>",
        "description": null
      },
      {
        "name": "OnDateChange",
        "type": "EventCallback<GanttTask>",
        "description": null
      },
      {
        "name": "OnProgressChange",
        "type": "EventCallback<GanttTask>",
        "description": null
      },
      {
        "name": "OnInitError",
        "type": "EventCallback<string>",
        "description": null
      }
    ],
    "enums": [],
    "records": [],
    "cssVars": [
      "--color-border",
      "--color-card",
      "--color-destructive",
      "--radius"
    ],
    "examples": [
      {
        "title": "Basic project plan",
        "code": "<Gantt Tasks=\"_tasks\" ViewMode=\"GanttViewMode.Day\" Height=\"420px\" />\n\n@code {\n    private List<GanttTask> _tasks = new() {\n        new(\"research\",    \"Research\",    DateTime.Today,              DateTime.Today.AddDays(5)),\n        new(\"design\",      \"Design\",      DateTime.Today.AddDays(5),   DateTime.Today.AddDays(12), Dependencies: new[] { \"research\" }),\n        new(\"development\", \"Development\", DateTime.Today.AddDays(12),  DateTime.Today.AddDays(25), Dependencies: new[] { \"design\" }),\n        new(\"testing\",     \"Testing\",     DateTime.Today.AddDays(22),  DateTime.Today.AddDays(30), Dependencies: new[] { \"development\" }),\n        new(\"launch\",      \"Launch\",      DateTime.Today.AddDays(30),  DateTime.Today.AddDays(32), Dependencies: new[] { \"testing\" }),\n    };\n}"
      },
      {
        "title": "With progress bars",
        "code": "<Gantt Tasks=\"_tasks\" ViewMode=\"GanttViewMode.Day\" Height=\"420px\" />\n\n@code {\n    private List<GanttTask> _tasks = new() {\n        new(\"research\",    \"Research\",    DateTime.Today,             DateTime.Today.AddDays(5),  Progress: 100),\n        new(\"design\",      \"Design\",      DateTime.Today.AddDays(5),  DateTime.Today.AddDays(12), Progress: 60,  Dependencies: new[] { \"research\" }),\n        new(\"development\", \"Development\", DateTime.Today.AddDays(12), DateTime.Today.AddDays(25), Progress: 30,  Dependencies: new[] { \"design\" }),\n        // ...\n    };\n}"
      },
      {
        "title": "Drag to reschedule + change progress",
        "code": "<Gantt @bind-Tasks=\"_tasks\"\n       ViewMode=\"GanttViewMode.Day\"\n       OnDateChange=\"HandleDateChange\"\n       OnProgressChange=\"HandleProgressChange\" />\n\n@code {\n    private IEnumerable<GanttTask> _tasks = new List<GanttTask> { /* ... */ };\n    private GanttTask? _last;\n\n    Task HandleDateChange(GanttTask t)     { _last = t; StateHasChanged(); return Task.CompletedTask; }\n    Task HandleProgressChange(GanttTask t) { _last = t; StateHasChanged(); return Task.CompletedTask; }\n}"
      },
      {
        "title": "View modes",
        "code": "<Gantt Tasks=\"_tasks\" ViewMode=\"GanttViewMode.Week\" Height=\"420px\" />"
      }
    ],
    "subComponents": {},
    "parseFailed": false,
    "parseError": null
  },
  "$schema": "https://lumeo.nativ.sh/registry-component-schema.json",
  "key": "gantt",
  "docsUrl": "https://lumeo.nativ.sh/components/gantt",
  "sourceUrl": [
    {
      "file": "UI/Gantt/Gantt.razor",
      "url": "https://github.com/Brain2k-0005/Lumeo/tree/master/src/Lumeo.Gantt/UI/Gantt/Gantt.razor"
    },
    {
      "file": "UI/Gantt/GanttTypes.cs",
      "url": "https://github.com/Brain2k-0005/Lumeo/tree/master/src/Lumeo.Gantt/UI/Gantt/GanttTypes.cs"
    }
  ],
  "source": [
    {
      "path": "UI/Gantt/Gantt.razor",
      "content": "@namespace Lumeo\n@implements IAsyncDisposable\n@inject Lumeo.Services.IComponentInteropService Interop\n@inject Lumeo.Services.Localization.ILumeoLocalizer L\n\n@if (_initError is not null)\n{\n    <div class=\"@($\"flex items-center justify-center text-sm text-destructive border border-destructive/30 rounded-md bg-destructive/5 {Class}\".Trim())\" @attributes=\"AdditionalAttributes\">\n        <span>@_initError</span>\n    </div>\n}\nelse\n{\n    <div class=\"@($\"flex flex-col gap-3 rounded-md border border-border/60 bg-card p-3 min-w-0 w-full {Class}\".Trim())\" @attributes=\"AdditionalAttributes\" style=\"min-width: 0; width: 100%;\">\n        @* Lumeo-styled toolbar above the Frappe Gantt canvas. We suppress\n           Quarter Day / Half Day from the control bar to keep the common case\n           simple — power users can still pass them through the `ViewMode` param. *@\n        <div class=\"flex flex-wrap items-center justify-between gap-2\">\n            <ToggleGroup Type=\"ToggleGroup.ToggleGroupType.Single\"\n                         Variant=\"ToggleGroup.ToggleGroupVariant.Outline\"\n                         Size=\"ToggleGroup.ToggleGroupSize.Sm\"\n                         Value=\"@_toolbarViewValue\"\n                         ValueChanged=\"OnViewModeChangedAsync\">\n                <ToggleGroupItem Value=\"Day\">@L[\"Gantt.Day\"]</ToggleGroupItem>\n                <ToggleGroupItem Value=\"Week\">@L[\"Gantt.Week\"]</ToggleGroupItem>\n                <ToggleGroupItem Value=\"Month\">@L[\"Gantt.Month\"]</ToggleGroupItem>\n                <ToggleGroupItem Value=\"Year\">@L[\"Gantt.Year\"]</ToggleGroupItem>\n            </ToggleGroup>\n            @if (TrailingContent is not null)\n            {\n                <div class=\"flex items-center gap-2\">\n                    @TrailingContent\n                </div>\n            }\n        </div>\n\n        @* Grid wrapper with minmax(0, 1fr) — well-known trick to defeat the\n           min-content cascade without touching containment. The 1fr column\n           has min size 0, so the SVG inside cannot push the wrapper wider\n           than its parent.\n           Height: use max-height (cap) instead of fixed height so the chart\n           shrinks to fit its content (header + N tasks * row height) and\n           only scrolls vertically when the task list exceeds @Height. *@\n        <div style=\"display: grid; grid-template-columns: minmax(0, 1fr); width: 100%;\">\n            <div @ref=\"_hostRef\" class=\"lumeo-gantt-host\" style=\"overflow-x: auto; overflow-y: auto; max-height: @Height; min-width: 0;\"></div>\n        </div>\n    </div>\n}\n\n@code {\n    [Parameter] public IEnumerable<GanttTask>? Tasks { get; set; }\n    [Parameter] public EventCallback<IEnumerable<GanttTask>> TasksChanged { get; set; }\n    [Parameter] public GanttViewMode ViewMode { get; set; } = GanttViewMode.Day;\n    [Parameter] public EventCallback<GanttTask> OnTaskClick { get; set; }\n    [Parameter] public EventCallback<GanttTask> OnDateChange { get; set; }\n    [Parameter] public EventCallback<GanttTask> OnProgressChange { get; set; }\n    [Parameter] public string Height { get; set; } = \"500px\";\n    [Parameter] public bool Readonly { get; set; }\n    /// <summary>Highlight today with a vertical line and dot marker. Default true.</summary>\n    [Parameter] public bool TodayHighlight { get; set; } = true;\n    /// <summary>Override the pixel height of each task bar (default 22).</summary>\n    [Parameter] public int? BarHeight { get; set; }\n    /// <summary>Override the pixel width of each date column for the current view mode.</summary>\n    [Parameter] public int? ColumnWidth { get; set; }\n    /// <summary>\n    /// Per-task bar colour override. Return a CSS colour string (hex, rgb, or a\n    /// CSS variable reference like \"var(--color-destructive)\") or null to use the\n    /// primary theme colour.\n    /// </summary>\n    [Parameter] public Func<GanttTask, string?>? BarColor { get; set; }\n    /// <summary>\n    /// Optional grouping function. When set, tasks are sorted by group label and\n    /// a visual section-header row is injected before the first task in each group.\n    /// </summary>\n    [Parameter] public Func<GanttTask, string>? GroupBy { get; set; }\n    [Parameter] public RenderFragment? TrailingContent { get; set; }\n    [Parameter] public EventCallback<string> OnInitError { get; set; }\n    [Parameter] public string? Class { get; set; }\n    [Parameter(CaptureUnmatchedValues = true)] public Dictionary<string, object>? AdditionalAttributes { get; set; }\n\n    private ElementReference _hostRef;\n    private string? _initError;\n    private DotNetObjectReference<Gantt>? _selfRef;\n    private string? _instanceId;\n    private bool _initialized;\n    private int _lastTasksHash;\n    private GanttViewMode _currentViewMode;\n\n    // Snapshot of the current tasks used when the JS layer reports a drag\n    // or progress change — avoids reaching back into `Tasks` (which may have\n    // been replaced by the parent between render cycles).\n    private List<GanttTask> _tasks = new();\n\n    // The toolbar only exposes Day/Week/Month/Year. When the caller passes a\n    // QuarterDay / HalfDay view mode, we keep the toggle group unselected.\n    private string? _toolbarViewValue => _currentViewMode switch\n    {\n        GanttViewMode.Day => \"Day\",\n        GanttViewMode.Week => \"Week\",\n        GanttViewMode.Month => \"Month\",\n        GanttViewMode.Year => \"Year\",\n        _ => null,\n    };\n\n    protected override void OnInitialized()\n    {\n        _currentViewMode = ViewMode;\n        _tasks = SortedTasks(Tasks?.ToList() ?? new List<GanttTask>());\n        _lastTasksHash = ComputeTasksHash(_tasks);\n    }\n\n    // When GroupBy is set, sort tasks so that each group clusters together.\n    // The original relative order within a group is preserved (stable sort).\n    private List<GanttTask> SortedTasks(List<GanttTask> raw)\n    {\n        if (GroupBy is null) return raw;\n        return raw\n            .Select((t, i) => (t, i))\n            .OrderBy(x => GroupBy(x.t))\n            .ThenBy(x => x.i)\n            .Select(x => x.t)\n            .ToList();\n    }\n\n    protected override async Task OnParametersSetAsync()\n    {\n        if (!_initialized || _instanceId is null) return;\n\n        if (Tasks is not null)\n        {\n            var incoming = SortedTasks(Tasks.ToList());\n            var hash = ComputeTasksHash(incoming);\n            if (hash != _lastTasksHash)\n            {\n                _lastTasksHash = hash;\n                _tasks = incoming;\n                await Interop.GanttSetTasksAsync(_instanceId, incoming.Select(ToJsTask).Cast<object>());\n            }\n        }\n\n        if (ViewMode != _currentViewMode)\n        {\n            _currentViewMode = ViewMode;\n            await Interop.GanttChangeViewModeAsync(_instanceId, ViewMode.ToString());\n        }\n    }\n\n    protected override async Task OnAfterRenderAsync(bool firstRender)\n    {\n        if (!firstRender || _initialized) return;\n\n        _selfRef = DotNetObjectReference.Create(this);\n\n        var options = new\n        {\n            tasks = _tasks.Select(ToJsTask).ToArray(),\n            viewMode = ViewMode.ToString(),\n            @readonly = Readonly,\n            todayHighlight = TodayHighlight,\n            barHeight = BarHeight,\n            columnWidth = ColumnWidth,\n        };\n\n        try\n        {\n            _instanceId = await Interop.GanttInitAsync(_hostRef, _selfRef, options);\n            _initialized = true;\n        }\n        catch (Microsoft.JSInterop.JSException ex)\n        {\n            _initError = $\"Gantt initialization failed: {ex.Message}\";\n            Console.Error.WriteLine($\"[Lumeo Gantt] Init failed: {ex.Message}\");\n            if (OnInitError.HasDelegate)\n                await OnInitError.InvokeAsync(ex.Message);\n            StateHasChanged();\n        }\n    }\n\n    private object ToJsTask(GanttTask t)\n    {\n        // For milestones render as zero-duration (start == end) so the renderer\n        // picks them up and draws a diamond shape.\n        var end = t.IsMilestone ? t.Start : t.End;\n        return new\n        {\n            id = t.Id,\n            name = t.Name,\n            start = t.Start.ToString(\"yyyy-MM-dd\"),\n            end = end.ToString(\"yyyy-MM-dd\"),\n            progress = t.Progress,\n            dependencies = t.Dependencies ?? Array.Empty<string>(),\n            custom_class = t.CustomClass,\n            is_milestone = t.IsMilestone,\n            group_label = t.GroupLabel,\n            bar_color = BarColor?.Invoke(t),\n        };\n    }\n\n    private static int ComputeTasksHash(IEnumerable<GanttTask> tasks)\n    {\n        // Cheap identity hash — good enough to detect \"did the caller swap the\n        // tasks list?\" without a JS round-trip on every render.\n        var hash = new HashCode();\n        foreach (var t in tasks)\n        {\n            hash.Add(t.Id);\n            hash.Add(t.Name);\n            hash.Add(t.Start);\n            hash.Add(t.End);\n            hash.Add(t.Progress);\n            hash.Add(t.CustomClass);\n            hash.Add(t.IsMilestone);\n            hash.Add(t.GroupLabel);\n            if (t.Dependencies is not null)\n                foreach (var d in t.Dependencies) hash.Add(d);\n        }\n        return hash.ToHashCode();\n    }\n\n    private async Task OnViewModeChangedAsync(string? v)\n    {\n        if (_instanceId is null || string.IsNullOrEmpty(v)) return;\n        if (!Enum.TryParse<GanttViewMode>(v, out var parsed)) return;\n        _currentViewMode = parsed;\n        await Interop.GanttChangeViewModeAsync(_instanceId, parsed.ToString());\n    }\n\n    [JSInvokable]\n    public async Task JsOnTaskClick(GanttTask t)\n    {\n        if (OnTaskClick.HasDelegate) await OnTaskClick.InvokeAsync(t);\n    }\n\n    [JSInvokable]\n    public async Task JsOnDateChange(GanttTask t)\n    {\n        ReplaceTask(t);\n        if (OnDateChange.HasDelegate) await OnDateChange.InvokeAsync(t);\n        if (TasksChanged.HasDelegate) await TasksChanged.InvokeAsync(_tasks.ToList());\n    }\n\n    [JSInvokable]\n    public async Task JsOnProgressChange(GanttTask t)\n    {\n        ReplaceTask(t);\n        if (OnProgressChange.HasDelegate) await OnProgressChange.InvokeAsync(t);\n        if (TasksChanged.HasDelegate) await TasksChanged.InvokeAsync(_tasks.ToList());\n    }\n\n    private void ReplaceTask(GanttTask t)\n    {\n        var idx = _tasks.FindIndex(x => x.Id == t.Id);\n        if (idx >= 0) _tasks[idx] = t;\n        _lastTasksHash = ComputeTasksHash(_tasks);\n    }\n\n    public async ValueTask DisposeAsync()\n    {\n        if (_instanceId is not null)\n        {\n            try { await Interop.GanttDestroyAsync(_instanceId); }\n            catch (Microsoft.JSInterop.JSDisconnectedException) { }\n        }\n        _selfRef?.Dispose();\n    }\n}\n"
    },
    {
      "path": "UI/Gantt/GanttTypes.cs",
      "content": "namespace Lumeo;\n\n/// <summary>\n/// A task bar rendered on the Gantt chart. Used as the data contract between\n/// Blazor and the Lumeo SVG Gantt renderer.\n/// </summary>\npublic record GanttTask(\n    string Id,\n    string Name,\n    DateTime Start,\n    DateTime End,\n    int Progress = 0,                // 0-100\n    string[]? Dependencies = null,   // array of Task Ids\n    string? CustomClass = null,\n    bool IsMilestone = false,        // renders as a diamond; zero-duration point event\n    string? GroupLabel = null        // optional swim-lane / group header label\n);\n\n/// <summary>\n/// Gantt timeline zoom level. Supported by the Lumeo SVG engine:\n/// QuarterDay = 6-hour columns, HalfDay = 12-hour columns,\n/// Day = 1 column/day, Week = 1 column/week,\n/// Month = 1 column/month, Year = 1 column/year.\n/// </summary>\npublic enum GanttViewMode\n{\n    QuarterDay,\n    HalfDay,\n    Day,\n    Week,\n    Month,\n    Year\n}\n"
    }
  ],
  "slots": [
    {
      "name": "TrailingContent",
      "owner": "Gantt",
      "type": "RenderFragment?",
      "description": null
    }
  ],
  "serviceDependencies": [
    {
      "service": "IComponentInteropService",
      "namespace": "Lumeo.Services"
    },
    {
      "service": "ILumeoLocalizer",
      "namespace": "Lumeo.Services.Localization"
    }
  ],
  "cascadingDependencies": [],
  "relatedComponents": [
    {
      "name": "ToggleGroup",
      "reason": "used internally"
    }
  ],
  "keyboardInteractions": [],
  "tests": [
    "tests/Lumeo.Docs.Tests/Helpers/DocsTestContext.cs",
    "tests/Lumeo.Tests/Components/Gantt/GanttTests.cs"
  ],
  "mdSummary": "# Gantt\n\nGantt component.\n\n**Package:** `Lumeo.Gantt` · **Category:** Data Display/Lists & Trees\n**Docs:** https://lumeo.nativ.sh/components/gantt\n\n## Parameters\n| Owner | Name | Type | Default | Description |\n|---|---|---|---|---|\n| Gantt | Tasks | `IEnumerable<GanttTask>?` | `` |  |\n| Gantt | TasksChanged | `EventCallback<IEnumerable<GanttTask>>` | `` |  |\n| Gantt | ViewMode | `GanttViewMode` | `GanttViewMode.Day` |  |\n| Gantt | OnTaskClick | `EventCallback<GanttTask>` | `` |  |\n| Gantt | OnDateChange | `EventCallback<GanttTask>` | `` |  |\n| Gantt | OnProgressChange | `EventCallback<GanttTask>` | `` |  |\n| Gantt | Height | `string` | `\"500px\"` |  |\n| Gantt | Readonly | `bool` | `` |  |\n| Gantt | TodayHighlight | `bool` | `true` | Highlight today with a vertical line and dot marker. Default true. |\n| Gantt | BarHeight | `int?` | `` | Override the pixel height of each task bar (default 22). |\n| Gantt | ColumnWidth | `int?` | `` | Override the pixel width of each date column for the current view mode. |\n| Gantt | BarColor | `Func<GanttTask, string?>?` | `` | Per-task bar colour override. Return a CSS colour string (hex, rgb, or a CSS variable reference like \"var(--color-destructive)\") or null to use the primary theme colour. |\n| Gantt | GroupBy | `Func<GanttTask, string>?` | `` | Optional grouping function. When set, tasks are sorted by group label and a visual section-header row is injected before the first task in each group. |\n| Gantt | TrailingContent | `RenderFragment?` | `` |  |\n| Gantt | OnInitError | `EventCallback<string>` | `` |  |\n| Gantt | Class | `string?` | `` |  |\n| Gantt | AdditionalAttributes | `Dictionary<string, object>?` | `` |  |\n\n## Slots\n- `TrailingContent` (Gantt) — RenderFragment slot\n\n## Events\n- `TasksChanged` (`EventCallback<IEnumerable<GanttTask>>`)\n- `OnTaskClick` (`EventCallback<GanttTask>`)\n- `OnDateChange` (`EventCallback<GanttTask>`)\n- `OnProgressChange` (`EventCallback<GanttTask>`)\n- `OnInitError` (`EventCallback<string>`)\n\n## Sub-components\n- (none)\n\n## Cascading values it expects\n- (none)\n\n## Services it injects\n- `IComponentInteropService` (Lumeo.Services)\n- `ILumeoLocalizer` (Lumeo.Services.Localization)\n\n## Keyboard\n—\n\n## Example\n```razor\n<Gantt />\n```\n\n## CSS variables\n`--color-border`, `--color-card`, `--color-destructive`, `--radius`\n\n## Files\n- `UI/Gantt/Gantt.razor`\n- `UI/Gantt/GanttTypes.cs`\n"
}