diff --git a/src/BootstrapBlazor/Components/DateTimePicker/DateTimePicker.razor b/src/BootstrapBlazor/Components/DateTimePicker/DateTimePicker.razor index 3cde0ba1564..f6883d0b98c 100644 --- a/src/BootstrapBlazor/Components/DateTimePicker/DateTimePicker.razor +++ b/src/BootstrapBlazor/Components/DateTimePicker/DateTimePicker.razor @@ -1,4 +1,4 @@ -@namespace BootstrapBlazor.Components +@namespace BootstrapBlazor.Components @typeparam TValue @inherits PopoverDropdownBase @attribute [BootstrapModuleAutoLoader("DateTimePicker/DateTimePicker.razor.js", JSObjectReference = true)] @@ -23,6 +23,10 @@ { } + @if (GetClearable()) + { + + } } /// private string? ClassString => CssBuilder.Default("select datetime-picker") .AddClass("disabled", IsDisabled) + .AddClass("is-clearable", GetClearable()) .AddClass(ValidCss) .AddClassFromAttributes(AdditionalAttributes) .Build(); @@ -46,6 +47,12 @@ public partial class DateTimePicker .AddClass(Icon) .Build(); + private string? ClearClassString => CssBuilder.Default("clear-icon") + .AddClass($"text-{Color.ToDescriptionString()}", Color != Color.None) + .AddClass("text-success", IsValid.HasValue && IsValid.Value) + .AddClass("text-danger", IsValid.HasValue && !IsValid.Value) + .Build(); + private string? TabIndexString => ValidateForm != null ? "0" : null; /// @@ -144,6 +151,21 @@ public string? Format [Parameter] public bool ShowIcon { get; set; } = true; + /// + /// 获得/设置 是否显示清除图标 默认 true 显示 + /// Gets or sets whether to show the clear icon. Default is true + /// + [Parameter] + public bool IsClearable { get; set; } = true; + + /// + /// 获得/设置 清除图标 默认使用内置主题图标 + /// Gets or sets the clear icon. The built-in theme icon is used by default + /// + [Parameter] + [NotNull] + public string? ClearIcon { get; set; } + /// /// 获得/设置 控件边框颜色样式 默认为 None 显示 /// Gets or sets Component Border Color Style. Default is None @@ -358,6 +380,7 @@ protected override void OnParametersSet() PickerButtonText ??= Localizer[nameof(PickerButtonText)]; Icon ??= IconTheme.GetIconByKey(ComponentIcons.DateTimePickerIcon); + ClearIcon ??= IconTheme.GetIconByKey(ComponentIcons.InputClearIcon); var type = typeof(TValue); @@ -488,6 +511,8 @@ protected override string FormatValueAsString(TValue? value) private bool MinValueToToday(DateTime val) => val == DateTime.MinValue && !AllowNull && AutoToday; + private bool GetClearable() => IsClearable && AllowNull && !IsDisabled && !IsButton; + /// /// 清除内部缓存方法 /// Clear Internal Cache Method diff --git a/src/BootstrapBlazor/Components/DateTimePicker/DateTimePicker.razor.scss b/src/BootstrapBlazor/Components/DateTimePicker/DateTimePicker.razor.scss index 936563b46b8..92d09b6a2bd 100644 --- a/src/BootstrapBlazor/Components/DateTimePicker/DateTimePicker.razor.scss +++ b/src/BootstrapBlazor/Components/DateTimePicker/DateTimePicker.razor.scss @@ -1,4 +1,4 @@ -@use "../../wwwroot/scss/variables" as *; +@use "../../wwwroot/scss/variables" as *; .datetime-picker { --bb-dt-picker-bar-color: #{$bb-dt-picker-bar-color}; @@ -19,6 +19,20 @@ } } + &.is-clearable { + &:hover { + .form-control { + &.is-invalid { + background-image: none; + } + + &.is-valid { + background-image: none; + } + } + } + } + .picker-panel { display: none } diff --git a/src/BootstrapBlazor/Components/ValidateForm/ValidateForm.razor.js b/src/BootstrapBlazor/Components/ValidateForm/ValidateForm.razor.js index aa8c8a88293..a04e4f763af 100644 --- a/src/BootstrapBlazor/Components/ValidateForm/ValidateForm.razor.js +++ b/src/BootstrapBlazor/Components/ValidateForm/ValidateForm.razor.js @@ -3,15 +3,17 @@ import Data from "../../modules/data.js" export function init(id) { const el = document.getElementById(id); - if (el) { - Data.set(id, { - el - }); - - const dissubmit = el.getAttribute('data-bb-dissubmit') === 'true'; - if (dissubmit) { - bind(el); - } + if (el === null) { + return; + } + + Data.set(id, { + el + }); + + const dissubmit = el.getAttribute('data-bb-dissubmit') === 'true'; + if (dissubmit) { + bind(el); } } diff --git a/test/UnitTest/Components/DateTimePickerTest.cs b/test/UnitTest/Components/DateTimePickerTest.cs index 1c87db701f5..eb848ba4541 100644 --- a/test/UnitTest/Components/DateTimePickerTest.cs +++ b/test/UnitTest/Components/DateTimePickerTest.cs @@ -186,6 +186,39 @@ public async Task OnClear_Ok() await cut.InvokeAsync(() => clear.Click()); } + [Fact] + public async Task ClearIcon_Ok() + { + DateTime? value = DateTime.Today; + var cut = Context.Render>(pb => + { + pb.Add(a => a.Value, value); + pb.Add(a => a.ValueChanged, v => value = v); + pb.Add(a => a.IsClearable, true); + pb.Add(a => a.ClearIcon, "clear-icon-test"); + }); + + cut.Contains("is-clearable"); + cut.Contains("clear-icon-test"); + + await cut.InvokeAsync(() => cut.Find(".clear-icon").Click()); + Assert.Null(value); + Assert.Equal(string.Empty, cut.Find(".datetime-picker-input").GetAttribute("value")); + + cut.Render(pb => pb.Add(a => a.IsDisabled, true)); + Assert.Empty(cut.FindAll(".clear-icon")); + + cut.Render(pb => + { + pb.Add(a => a.IsDisabled, false); + pb.Add(a => a.IsButton, true); + }); + Assert.Empty(cut.FindAll(".clear-icon")); + + var nonNullable = Context.Render>(pb => pb.Add(a => a.IsClearable, true)); + Assert.Empty(nonNullable.FindAll(".clear-icon")); + } + [Fact] public void ShowSiderBar_Ok() {