Repository: ant-design-blazor/ant-design-blazor (csharp)

Issue:
TimelineItem color specified as string throws exception
### Describe the bug

When I specify color to `Color` parameter of `TimeLineItem` component, it will throw an `InvalidOperationException`.

Type of `Color` parameter is `OneOf<TimelineDotColor, string>`, so `string` value should work. 

I observe this behavior after upgrading to `1.*` version.

### Steps to reproduce (please include code)

```razor
<div>
  <Timeline>
    @foreach (var num in Enumerable.Range(1, 10))
    {
      const string col = "red";
      <TimelineItem Color="@col">Item @num</TimelineItem>
    }
  </Timeline>
</div>
```

Minimal repro: https://github.com/GodEmperorOfTime/AntTimelineIssue/blob/master/AntTimelineIssue/Components/Pages/Home.razor

### Exceptions (if any)

`InvalidOperationException: Cannot return as T0 as result is T1`

Callstack:
```
OneOf.OneOf<T0, T1>.get_AsT0()
AntDesign.TimelineItem.SetClassMap()
AntDesign.TimelineItem.OnParametersSet()
Microsoft.AspNetCore.Components.ComponentBase.CallOnParametersSetAsync()
... (bazillion Microsoft.AspNetCore.* calls)
```

<!-- 
Include the exception you get when facing this issue
-->

### Further technical details

#### NuGet Version

```xml
<PackageReference Include="AntDesign" Version="1.1.2" />
```

#### dotnet --info

```
.NET SDK:
 Version:           9.0.101
 Commit:            eedb237549
 Workload version:  9.0.100-manifests.4a280210
 MSBuild version:   17.12.12+1cce77968

Runtime Environment:
 OS Name:     Windows
 OS Version:  10.0.19045
 OS Platform: Windows
 RID:         win-x64
 Base Path:   C:\Program Files\dotnet\sdk\9.0.101\

.NET workloads installed:
 [wasm-tools-net8]
   Installation Source: VS 17.12.35527.113
   Manifest Version:    9.0.0/9.0.100
   Manifest Path:       C:\Program Files\dotnet\sdk-manifests\9.0.100\microsoft.net.workload.mono.toolchain.net8\9.0.0\WorkloadManifest.json
   Install Type:              Msi

 [aspire]
   Installation Source: VS 17.12.35527.113
   Manifest Version:    8.2.2/8.0.100
   Manifest Path:       C:\Program Files\dotnet\sdk-manifests\8.0.100\microsoft.net.sdk.aspire\8.2.2\WorkloadManifest.json
   Install Type:              Msi

 [wasm-tools]
   Installation Source: VS 17.12.35527.113
   Manifest Version:    9.0.0/9.0.100
   Manifest Path:       C:\Program Files\dotnet\sdk-manifests\9.0.100\microsoft.net.workload.mono.toolchain.current\9.0.0\WorkloadManifest.json
   Install Type:              Msi

Configured to use loose manifests when installing new manifests.

Host:
  Version:      9.0.0
  Architecture: x64
  Commit:       9d5a6a9aa4

.NET SDKs installed:
  3.1.426 [C:\Program Files\dotnet\sdk]
  5.0.408 [C:\Program Files\dotnet\sdk]
  6.0.202 [C:\Program Files\dotnet\sdk]
  6.0.203 [C:\Program Files\dotnet\sdk]
  6.0.319 [C:\Program Files\dotnet\sdk]
  8.0.404 [C:\Program Files\dotnet\sdk]
  9.0.101 [C:\Program Files\dotnet\sdk]

.NET runtimes installed:
  Microsoft.AspNetCore.All 2.1.30 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
  Microsoft.AspNetCore.App 2.1.30 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 3.1.28 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 3.1.30 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 3.1.32 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 5.0.17 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 6.0.5 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 6.0.8 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 6.0.10 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 6.0.24 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 6.0.36 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 7.0.20 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 8.0.11 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 9.0.0 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.NETCore.App 2.1.30 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 3.1.28 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 3.1.30 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 3.1.32 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 5.0.17 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 6.0.4 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 6.0.5 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 6.0.8 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 6.0.10 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 6.0.15 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 6.0.35 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 6.0.36 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 7.0.20 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 8.0.11 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 9.0.0 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.WindowsDesktop.App 3.1.28 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 3.1.30 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 3.1.32 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 5.0.17 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 6.0.4 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 6.0.5 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 6.0.8 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 6.0.10 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 6.0.15 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 6.0.24 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 6.0.36 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 7.0.20 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 8.0.11 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 9.0.0 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]

Other architectures found:
  x86   [C:\Program Files (x86)\dotnet]
    registered at [HKLM\SOFTWARE\dotnet\Setup\InstalledVersions\x86\InstallLocation]

Environment variables:
  Not set

global.json file:
  Not found

Learn more:
  https://aka.ms/dotnet/info

Download .NET:
  https://aka.ms/dotnet/download
```

#### IDE:

Visual Studio 17.12.3

Pull request description:
<!--
First of all, thank you for your contribution! 😄

New feature please send pull request to feature branch, and rest to master branch.
Pull request will be merged after one of collaborators approve.
Please makes sure that these form are filled before submitting your pull request, thank you!

[[中文版模板 / Chinese template](https://github.com/ant-design-blazor/ant-design-blazor/blob/master/.github/PULL_REQUEST_TEMPLATE/pr_cn.md)]

-->

### 🤔 This is a ...

- [ ] New feature
- [x] Bug fix
- [ ] Site / documentation update
- [ ] Demo update
- [ ] Component style update
- [ ] Bundle size optimization
- [ ] Performance optimization
- [ ] Refactoring
- [ ] Code style optimization
- [ ] Test Case
- [ ] Branch merge
- [ ] Other (about what?)

### 🔗 Related issue link

<!--
1. Describe the source of requirement, like related issue link.
-->

fixed #4432

### 💡 Background and solution

<!--
1. Describe the problem and the scenario.
2. GIF or snapshot should be provided if includes UI/interactive modification.
3. How to fix the problem, and list final API implementation and usage sample if that is an new feature.
-->

### 📝 Changelog

<!--
Describe changes from userside, and list all potential break changes or other risks.
--->

| Language   | Changelog |
| ---------- | --------- |
| 🇺🇸 English |           |
| 🇨🇳 Chinese |           |

### ☑️ Self Check before Merge

⚠️ Please check all items below before review. ⚠️

- [ ] Doc is updated/provided or not needed
- [ ] Demo is updated/provided or not needed
- [ ] Changelog is provided or not needed

Patch:
diff --git a/components/timeline/Timeline.razor.cs b/components/timeline/Timeline.razor.cs
index 99c8016b5e..b756330585 100644
--- a/components/timeline/Timeline.razor.cs
+++ b/components/timeline/Timeline.razor.cs
@@ -98,7 +98,6 @@ public OneOf<string, RenderFragment> Pending
                         _pendingItem.SetChildContent(rf);
                     });
 
-                    _pendingItem?.SetClassMap();
                     _waitingItemUpdate = true;
                 }
             }
@@ -206,8 +205,6 @@ protected IEnumerable<TimelineItem> UpdateChildren(IEnumerable<TimelineItem> ite
                     _ => null,
                 };
 
-                item.SetClassMap();
-
                 yield return item;
             }
         }
diff --git a/components/timeline/TimelineItem.cs b/components/timeline/TimelineItem.cs
index 67b839904d..d39b54b36e 100644
--- a/components/timeline/TimelineItem.cs
+++ b/components/timeline/TimelineItem.cs
@@ -2,7 +2,6 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 // See the LICENSE file in the project root for more information.
 
-using System.Linq;
 using Microsoft.AspNetCore.Components;
 using OneOf;
 
@@ -59,18 +58,18 @@ protected override void OnInitialized()
             ParentTimeline?.AddItem(this);
             this.TryUpdateCustomColor();
             base.OnInitialized();
+            SetClassMap();
         }
 
         protected override void OnParametersSet()
         {
-            this.SetClassMap();
             this.TryUpdateCustomColor();
             base.OnParametersSet();
         }
 
         private void TryUpdateCustomColor()
         {
-            HeadStyle = !Color.IsT0 ? $"border-color:{Color}" : "";
+            HeadStyle = Color.IsT1 ? $"border-color:{Color.AsT1}" : "";
         }
 
         internal void SetClassMap()
@@ -82,8 +81,8 @@ internal void SetClassMap()
                 .If($"{prefix}-last", () => IsLast);
 
             var headPrefix = "ant-timeline-item-head";
-            _headClassMapper.Clear().Add(headPrefix)
-                .If($"{headPrefix}-{Color.AsT0.ToString().ToLowerInvariant()}", () => Color.IsT0)
+            _headClassMapper.Add(headPrefix)
+                .GetIf(() => $"{headPrefix}-{Color.AsT0.ToString().ToLowerInvariant()}", () => Color.IsT0)
                 .If($"{headPrefix}-custom", () => Dot != null);
         }
 
diff --git a/site/AntDesign.Docs/Demos/Components/Timeline/demo/Color.md b/site/AntDesign.Docs/Demos/Components/Timeline/demo/Color.md
index 37247c9eb4..4c931889d2 100644
--- a/site/AntDesign.Docs/Demos/Components/Timeline/demo/Color.md
+++ b/site/AntDesign.Docs/Demos/Components/Timeline/demo/Color.md
@@ -6,8 +6,14 @@ title:
 ---
 
 ## zh-CN
-圆圈颜色，`绿色`用于已完成、成功状态，`红色`表示告警或错误状态，`蓝色`可表示正在进行或其他默认状态，`灰色`表示未完成或失效状态。
+预设颜色中，`绿色`用于已完成、成功状态，`红色`表示告警或错误状态，`蓝色`可表示正在进行或其他默认状态，`灰色`表示未完成或失效状态。
+
+另外还支持自定义颜色。
 
 
 ## en-US
-Set the color of circles. `green` means completed or success status, `red` means warning or error, and `blue` means ongoing or other default status, `gray` for unfinished or disabled status.
+The preset colors are `green` means completed or success status, `red` means warning or error, and `blue` means ongoing or other default status, `gray` for unfinished or disabled status.
+
+You can also set custom colors.
+
+
diff --git a/site/AntDesign.Docs/Demos/Components/Timeline/demo/Color.razor b/site/AntDesign.Docs/Demos/Components/Timeline/demo/Color.razor
index d36138bff2..268a02ad6f 100644
--- a/site/AntDesign.Docs/Demos/Components/Timeline/demo/Color.razor
+++ b/site/AntDesign.Docs/Demos/Components/Timeline/demo/Color.razor
@@ -17,7 +17,7 @@
             <p>Technical testing 2</p>
             <p>Technical testing 3 2015-09-01</p>
         </TimelineItem>
-        <TimelineItem Color="TimelineDotColor.Gray">
+        <TimelineItem Color="@("#f50")">
             <p>Technical testing 1</p>
             <p>Technical testing 2</p>
             <p>Technical testing 3 2015-09-01</p>


Test patch:
diff --git a/tests/AntDesign.Tests/Timeline/TimelineTests.razor b/tests/AntDesign.Tests/Timeline/TimelineTests.razor
index b2c038d57f..20e0425286 100644
--- a/tests/AntDesign.Tests/Timeline/TimelineTests.razor
+++ b/tests/AntDesign.Tests/Timeline/TimelineTests.razor
@@ -125,4 +125,72 @@
 			  </li>
 			</ul> );
 	}
+    
+    [Theory]
+    [InlineData(TimelineDotColor.Red,"red")]
+    [InlineData(TimelineDotColor.Green,"green")]
+    public void Renders_timeline_with_color(TimelineDotColor color, string expectedColor)
+    {
+        var cut = Context.Render(
+            @<Timeline >
+                <TimelineItem Label="2015-09-01" >Create a services site</TimelineItem>
+                <TimelineItem Label="2015-09-02" Color="@color" >Solve initial network problems</TimelineItem>
+            </Timeline>);
+
+        cut.MarkupMatches(
+            @<ul class="ant-timeline ant-timeline-label" id:ignore >
+                <li class="ant-timeline-item" id:ignore >
+                    <div class="ant-timeline-item-label">2015-09-01</div>
+                    <div class="ant-timeline-item-tail"></div>
+                    <div class="ant-timeline-item-head ant-timeline-item-head-blue" style="">
+                    </div>
+                    <div class="ant-timeline-item-content">
+                        Create a services site 
+                    </div>
+                </li>
+                <li class="ant-timeline-item ant-timeline-item-last" id:ignore >
+                    <div class="ant-timeline-item-label">2015-09-02</div>
+                    <div class="ant-timeline-item-tail"></div>
+                    <div class="ant-timeline-item-head ant-timeline-item-head-@expectedColor" style="">
+                    </div>
+                    <div class="ant-timeline-item-content">
+                        Solve initial network problems 
+                    </div>
+                </li>
+            </ul> );
+    }
+    
+    [Theory]
+    [InlineData("#fff")]
+    [InlineData("green")]
+    public void Renders_timeline_with_custom_color(string color)
+    {
+        var cut = Context.Render(
+            @<Timeline >
+                <TimelineItem Label="2015-09-01" >Create a services site</TimelineItem>
+                <TimelineItem Label="2015-09-02" Color="@color" >Solve initial network problems</TimelineItem>
+            </Timeline>);
+
+        cut.MarkupMatches(
+            @<ul class="ant-timeline ant-timeline-label" id:ignore >
+                <li class="ant-timeline-item" id:ignore >
+                    <div class="ant-timeline-item-label">2015-09-01</div>
+                    <div class="ant-timeline-item-tail"></div>
+                    <div class="ant-timeline-item-head ant-timeline-item-head-blue" style="">
+                    </div>
+                    <div class="ant-timeline-item-content">
+                        Create a services site 
+                    </div>
+                </li>
+                <li class="ant-timeline-item ant-timeline-item-last" id:ignore >
+                    <div class="ant-timeline-item-label">2015-09-02</div>
+                    <div class="ant-timeline-item-tail"></div>
+                    <div class="ant-timeline-item-head" style="border-color:@color">
+                    </div>
+                    <div class="ant-timeline-item-content">
+                        Solve initial network problems 
+                    </div>
+                </li>
+            </ul> );
+    }
 }
\ No newline at end of file
diff --git a/tests/AntDesign.Tests/_Imports.razor b/tests/AntDesign.Tests/_Imports.razor
index 4fd8383f2b..97205fba24 100644
--- a/tests/AntDesign.Tests/_Imports.razor
+++ b/tests/AntDesign.Tests/_Imports.razor
@@ -9,4 +9,5 @@
 @using Moq
 @using AntDesign
 @using AntDesign.JsInterop
-@using FluentAssertions
\ No newline at end of file
+@using FluentAssertions
+@using OneOf
\ No newline at end of file