diff --git a/docs/CodeBeam.MudBlazor.Extensions.Docs.Wasm/wwwroot/CodeBeam.MudBlazor.Extensions.xml b/docs/CodeBeam.MudBlazor.Extensions.Docs.Wasm/wwwroot/CodeBeam.MudBlazor.Extensions.xml
index c79cee8a..762f518c 100644
--- a/docs/CodeBeam.MudBlazor.Extensions.Docs.Wasm/wwwroot/CodeBeam.MudBlazor.Extensions.xml
+++ b/docs/CodeBeam.MudBlazor.Extensions.Docs.Wasm/wwwroot/CodeBeam.MudBlazor.Extensions.xml
@@ -1387,7 +1387,7 @@
The current month shown in the date picker.
- Defaults to the current month.
+ Defaults to the current month.
When bound via @bind-PickerMonth, controls the initial month displayed. This value is always the first day of a month.
@@ -1401,7 +1401,7 @@
The delay, in milliseconds, before closing the picker after a value is selected.
- Defaults to 100.
+ Defaults to 100.
This delay helps the user see that a date has been selected before the popover disappears.
@@ -1418,7 +1418,7 @@
The maximum number of months allowed in one row.
- Defaults to null.
+ Defaults to null.
When null, the is used.
@@ -1440,7 +1440,7 @@
The format of the selected date in the title.
- Defaults to ddd, dd MMM.
+ Defaults to ddd, dd MMM.
Supported date formats can be found here: .
@@ -1457,7 +1457,7 @@
The function used to disable one or more dates.
- Defaults to null.
+ Defaults to null.
When set, a date will be disabled if the function returns true.
@@ -1599,9 +1599,9 @@
Shows a 12-hour selection clock.
- Defaults to false.
- When true, hours 1-12 are displayed with an AM or PM marker.
- When false, hours 0-23 are displayed.
+ Defaults to false.
+ When true, hours 1-12 are displayed with an AM or PM marker.
+ When false, hours 0-23 are displayed.
diff --git a/docs/CodeBeam.MudBlazor.Extensions.Docs/Pages/Components/DateTimePicker/DateTimePickerPage.razor b/docs/CodeBeam.MudBlazor.Extensions.Docs/Pages/Components/DateTimePicker/DateTimePickerPage.razor
index a2daa74d..abe7efff 100644
--- a/docs/CodeBeam.MudBlazor.Extensions.Docs/Pages/Components/DateTimePicker/DateTimePickerPage.razor
+++ b/docs/CodeBeam.MudBlazor.Extensions.Docs/Pages/Components/DateTimePicker/DateTimePickerPage.razor
@@ -5,7 +5,7 @@
-
+
diff --git a/docs/CodeBeam.MudBlazor.Extensions.Docs/Pages/Components/DateTimePicker/Examples/DateTimePickerExample2.razor b/docs/CodeBeam.MudBlazor.Extensions.Docs/Pages/Components/DateTimePicker/Examples/DateTimePickerExample2.razor
index e599abe7..2b8a39bf 100644
--- a/docs/CodeBeam.MudBlazor.Extensions.Docs/Pages/Components/DateTimePicker/Examples/DateTimePickerExample2.razor
+++ b/docs/CodeBeam.MudBlazor.Extensions.Docs/Pages/Components/DateTimePicker/Examples/DateTimePickerExample2.razor
@@ -3,11 +3,25 @@
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
@@ -19,9 +33,14 @@
@code {
- private DateTime? _date = DateTime.Now;
- private DateTimeOffset _date2 = DateTimeOffset.UtcNow;
- private DateOnly _date3 = DateOnly.FromDateTime(DateTime.Now);
+ private static readonly TimeZoneInfo IstanbulTimeZone = TimeZoneInfo.FindSystemTimeZoneById("Europe/Istanbul");
+ private DateTime _dateTime = DateTime.Now;
+ private DateTime? _nullableDateTime;
+ private DateTimeOffset _dateTimeOffset = DateTimeOffset.UtcNow;
+ private DateTimeOffset _istanbulDateTimeOffset = TimeZoneInfo.ConvertTime(DateTimeOffset.UtcNow, IstanbulTimeZone);
+ private DateTimeOffset? _nullableDateTimeOffset;
+ private DateOnly _dateOnly = DateOnly.FromDateTime(DateTime.Now);
+ private DateOnly? _nullableDateOnly;
private bool _clearable = false;
private bool _editable = false;
}
diff --git a/docs/CodeBeam.MudBlazor.Extensions.Docs/Pages/Components/DateTimePicker/Examples/DateTimePickerExample3.razor b/docs/CodeBeam.MudBlazor.Extensions.Docs/Pages/Components/DateTimePicker/Examples/DateTimePickerExample3.razor
index 2e0ca6d7..8e78683d 100644
--- a/docs/CodeBeam.MudBlazor.Extensions.Docs/Pages/Components/DateTimePicker/Examples/DateTimePickerExample3.razor
+++ b/docs/CodeBeam.MudBlazor.Extensions.Docs/Pages/Components/DateTimePicker/Examples/DateTimePickerExample3.razor
@@ -3,14 +3,61 @@
-
-
- Clear
- Cancel
- OK
-
-
+
+
+
+ Clear
+ Cancel
+ OK
+
+
+
+
+
+ Clear
+ Cancel
+ OK
+
+
+
+
+
+ Clear
+ Cancel
+ OK
+
+
+
+
+
+ Clear
+ Cancel
+ OK
+
+
+
+
+
+ Clear
+ Cancel
+ OK
+
+
+
+
+
+ Clear
+ Cancel
+ OK
+
+
+
@@ -32,15 +79,25 @@
}
- Set Today
+ Set Current Values
@code {
- private MudDateTimePicker _picker = null!;
+ private MudDateTimePicker _dateTimePicker = null!;
+ private MudDateTimePicker _nullableDateTimePicker = null!;
+ private MudDateTimePicker _dateTimeOffsetPicker = null!;
+ private MudDateTimePicker _nullableDateTimeOffsetPicker = null!;
+ private MudDateTimePicker _dateOnlyPicker = null!;
+ private MudDateTimePicker _nullableDateOnlyPicker = null!;
- private DateTime? _date = DateTime.Now;
+ private DateTime _dateTime = DateTime.Now;
+ private DateTime? _nullableDateTime;
+ private DateTimeOffset _dateTimeOffset = DateTimeOffset.UtcNow;
+ private DateTimeOffset? _nullableDateTimeOffset;
+ private DateOnly _dateOnly = DateOnly.FromDateTime(DateTime.Now);
+ private DateOnly? _nullableDateOnly;
private bool _editable = false;
private bool _showToolbar = true;
private bool _submitOnClose = true;
@@ -49,4 +106,16 @@
private bool _isAdornmentEnd = true;
private bool _clearable = false;
private Variant _variant = Variant.Outlined;
+
+ private void SetCurrentValues()
+ {
+ _dateTime = DateTime.Now;
+ _nullableDateTime = DateTime.Now;
+ _dateTimeOffset = DateTimeOffset.UtcNow;
+ _nullableDateTimeOffset = DateTimeOffset.UtcNow;
+ _dateOnly = DateOnly.FromDateTime(DateTime.Now);
+ _nullableDateOnly = DateOnly.FromDateTime(DateTime.Now);
+ }
}
+
+
\ No newline at end of file
diff --git a/src/CodeBeam.MudBlazor.Extensions/CodeBeam.MudBlazor.Extensions.csproj b/src/CodeBeam.MudBlazor.Extensions/CodeBeam.MudBlazor.Extensions.csproj
index 360039a8..4ea95298 100644
--- a/src/CodeBeam.MudBlazor.Extensions/CodeBeam.MudBlazor.Extensions.csproj
+++ b/src/CodeBeam.MudBlazor.Extensions/CodeBeam.MudBlazor.Extensions.csproj
@@ -58,7 +58,7 @@
<_Parameter1>CodeBeam.MudBlazor.Extensions.UnitTests
-
+
True
diff --git a/src/CodeBeam.MudBlazor.Extensions/Components/DateTimePicker/MudBaseDatePickerX.cs b/src/CodeBeam.MudBlazor.Extensions/Components/DateTimePicker/MudBaseDatePickerX.cs
index f6b9c008..b1800cd7 100644
--- a/src/CodeBeam.MudBlazor.Extensions/Components/DateTimePicker/MudBaseDatePickerX.cs
+++ b/src/CodeBeam.MudBlazor.Extensions/Components/DateTimePicker/MudBaseDatePickerX.cs
@@ -13,6 +13,9 @@ public abstract partial class MudBaseDatePickerX : MudPicker
{
internal readonly string _mudPickerCalendarContentElementId;
private readonly ParameterState _formatState;
+ ///
+ /// The unique identifier used to associate picker elements.
+ ///
protected readonly string _componentId = Identifier.Create();
internal DateTime? _picker_month;
@@ -107,7 +110,7 @@ protected MudBaseDatePickerX()
/// The current month shown in the date picker.
///
///
- /// Defaults to the current month.
+ /// Defaults to the current month.
/// When bound via @bind-PickerMonth, controls the initial month displayed. This value is always the first day of a month.
///
[Parameter]
@@ -133,7 +136,7 @@ public DateTime? PickerMonth
/// The delay, in milliseconds, before closing the picker after a value is selected.
///
///
- /// Defaults to 100.
+ /// Defaults to 100.
/// This delay helps the user see that a date has been selected before the popover disappears.
///
[Parameter] public int ClosingDelay { get; set; } = 100;
@@ -150,7 +153,7 @@ public DateTime? PickerMonth
/// The maximum number of months allowed in one row.
///
///
- /// Defaults to null.
+ /// Defaults to null.
/// When null, the is used.
///
[Parameter] public int? MaxMonthColumns { get; set; }
@@ -172,7 +175,7 @@ public DateTime? PickerMonth
/// The format of the selected date in the title.
///
///
- /// Defaults to ddd, dd MMM.
+ /// Defaults to ddd, dd MMM.
/// Supported date formats can be found here: .
///
[Parameter] public string TitleDateFormat { get; set; } = "ddd, dd MMM";
@@ -189,7 +192,7 @@ public DateTime? PickerMonth
/// The function used to disable one or more dates.
///
///
- /// Defaults to null.
+ /// Defaults to null.
/// When set, a date will be disabled if the function returns true.
///
[Parameter] public Func IsDateDisabledFunc { get; set; } = _ => false;
@@ -247,6 +250,17 @@ public DateTime? PickerMonth
///
protected internal bool IsDateOnly => (Nullable.GetUnderlyingType(typeof(T)) ?? typeof(T)) == typeof(DateOnly);
+ ///
+ /// Determines whether a non-nullable picker value is its default value.
+ ///
+ /// The value to evaluate.
+ /// when is non-nullable and equals its default value; otherwise, .
+ protected internal bool IsDefaultValue(T? value)
+ {
+ return Nullable.GetUnderlyingType(typeof(T)) is null &&
+ EqualityComparer.Default.Equals(value, default);
+ }
+
///
/// Generic conversion method to convert the generic type T to DateTime. Supports DateTime and DateTimeOffset.
///
@@ -306,6 +320,9 @@ public DateTime? PickerMonth
throw new NotSupportedException($"Type {typeof(T)} not supported");
}
+ ///
+ /// Validates that is a supported date type.
+ ///
protected void ValidateType()
{
var t = Nullable.GetUnderlyingType(typeof(T)) ?? typeof(T);
@@ -341,6 +358,11 @@ protected override async Task OnAfterRenderAsync(bool firstRender)
ScrollToYearAsync().CatchAndLog();
}
+ ///
+ /// Handles a change to the configured date format.
+ ///
+ /// The newly configured date format.
+ /// A task that represents the asynchronous operation.
protected virtual Task DateFormatChangedAsync(string? newFormat) => Task.CompletedTask;
private Task DateFormatChangedAsync(ParameterChangedEventArgs args) => DateFormatChangedAsync(args.Value);
@@ -358,13 +380,24 @@ protected override async Task OnAfterRenderAsync(bool firstRender)
|| CurrentView == OpenTo.Month
|| CurrentView == OpenTo.Year;
+ ///
protected override async Task OnPickerOpenedAsync()
{
await base.OnPickerOpenedAsync();
var dateTime = ToDateTime(_value);
- if (dateTime.HasValue)
+ if (IsDefaultValue(_value))
+ {
+ var culture = GetCulture();
+ var calendar = culture.Calendar;
+ PickerMonth = new DateTime(
+ calendar.GetYear(DateTime.Today),
+ calendar.GetMonth(DateTime.Today),
+ 1,
+ calendar);
+ }
+ else if (dateTime.HasValue)
{
var culture = GetCulture();
var calendar = culture.Calendar;
@@ -378,6 +411,11 @@ protected override async Task OnPickerOpenedAsync()
CurrentView = OpenTo;
}
+ ///
+ /// Gets the first day of the month at the specified offset from the displayed month.
+ ///
+ /// The zero-based offset from the displayed month.
+ /// The first day of the requested month.
protected DateTime GetMonthStart(int month)
{
var culture = GetCulture();
@@ -387,6 +425,12 @@ protected DateTime GetMonthStart(int month)
return calendar.AddMonths(new DateTime(baseDate.Year, baseDate.Month, 1), month);
}
+ ///
+ /// Gets the seven days displayed for a calendar week.
+ ///
+ /// The zero-based offset from the displayed month.
+ /// The zero-based week index.
+ /// The dates in the requested week.
protected IEnumerable GetWeek(int month, int index)
{
if (index is < 0 or > 5)
@@ -403,6 +447,11 @@ protected IEnumerable GetWeek(int month, int index)
yield return weekFirst.AddDays(i);
}
+ ///
+ /// Determines whether a date is unavailable for selection.
+ ///
+ /// The date to evaluate.
+ /// when the date is disabled; otherwise, .
protected virtual bool IsDayDisabled(DateTime date)
{
return date < MinDate ||
@@ -410,14 +459,35 @@ protected virtual bool IsDayDisabled(DateTime date)
IsDateDisabledFunc(date);
}
+ ///
+ /// Gets the CSS classes for a calendar day.
+ ///
+ /// The zero-based offset from the displayed month.
+ /// The day to format.
+ /// The CSS classes for the day.
protected abstract string GetDayClasses(int month, DateTime day);
+
+ ///
+ /// Handles selection of a calendar day.
+ ///
+ /// The selected date and time.
+ /// A task that represents the asynchronous operation.
protected abstract Task OnDayClickedAsync(DateTime dateTime);
+ ///
+ /// Formats a date for the picker title.
+ ///
+ /// The date to format.
+ /// The formatted title, or an empty string when is .
protected string FormatTitleDate(DateTime? date)
{
return date?.ToString(TitleDateFormat, GetCulture()) ?? "";
}
+ ///
+ /// Gets abbreviated day names ordered according to the configured first day of the week.
+ ///
+ /// The ordered abbreviated day names.
protected IEnumerable GetAbbreviatedDayNames()
{
var culture = GetCulture();
@@ -428,6 +498,7 @@ protected IEnumerable GetAbbreviatedDayNames()
return Enumerable.Range(0, 7).Select(i => names[(i + firstDay) % 7]);
}
+ ///
protected override IConverter GetDefaultConverter()
{
return new DefaultConverter
@@ -437,6 +508,7 @@ protected IEnumerable GetAbbreviatedDayNames()
};
}
+ ///
protected override string? ConvertSet(T? value)
{
var dt = ToDateTime(value);
@@ -447,6 +519,11 @@ protected IEnumerable GetAbbreviatedDayNames()
return dt.Value.ToString(GetFormat(), GetCulture());
}
+ ///
+ /// Converts a picker value to its display text.
+ ///
+ /// The value to convert.
+ /// The formatted text, or when the value has no date representation.
protected internal string? ConvertSetInternal(T? value)
{
return ConvertSet(value);
@@ -472,14 +549,33 @@ protected override string GetFormat()
return $"{CultureInfo.CurrentCulture.DateTimeFormat.ShortDatePattern} HH:mm";
}
+ ///
+ /// Gets the initial month shown by the calendar.
+ ///
+ /// The first day of the initial month.
protected abstract DateTime GetCalendarStartOfMonth();
+
+ ///
+ /// Gets the culture-specific calendar year for a date.
+ ///
+ /// The date whose calendar year is required.
+ /// The calendar year.
protected abstract int GetCalendarYear(DateTime yearDate);
+ ///
+ /// Gets the first day of the calendar week.
+ ///
+ /// The configured first day of the week, or the culture default.
protected DayOfWeek GetFirstDayOfWeek()
{
return FirstDayOfWeek ?? GetCulture().DateTimeFormat.FirstDayOfWeek;
}
+ ///
+ /// Gets the last day of the month at the specified offset from the displayed month.
+ ///
+ /// The zero-based offset from the displayed month.
+ /// The last day of the requested month.
protected DateTime GetMonthEnd(int month)
{
var culture = GetCulture();
@@ -503,4 +599,4 @@ public virtual Task ScrollToYearAsync(DateTime? date = null)
//{
// return JsApiService.UpdateStyleProperty(_mudPickerCalendarContentElementId, "--selected-day", tempId);
//}
-}
\ No newline at end of file
+}
diff --git a/src/CodeBeam.MudBlazor.Extensions/Components/DateTimePicker/MudDateTimePicker.razor.cs b/src/CodeBeam.MudBlazor.Extensions/Components/DateTimePicker/MudDateTimePicker.razor.cs
index d8049512..c7c3d9bc 100644
--- a/src/CodeBeam.MudBlazor.Extensions/Components/DateTimePicker/MudDateTimePicker.razor.cs
+++ b/src/CodeBeam.MudBlazor.Extensions/Components/DateTimePicker/MudDateTimePicker.razor.cs
@@ -16,6 +16,10 @@ public partial class MudDateTimePicker : MudBaseDatePickerX
{
[Inject] private IJSRuntime JsRuntime { get; set; } = null!;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
[DynamicDependency(nameof(OnStickClick))]
[DynamicDependency(nameof(SelectTimeFromStick))]
public MudDateTimePicker()
@@ -34,12 +38,25 @@ public MudDateTimePicker()
private record SetTime
{
+ ///
+ /// Gets or sets the selected hour.
+ ///
public int Hour { get; set; }
+
+ ///
+ /// Gets or sets the selected minute.
+ ///
public int Minute { get; set; }
}
+ ///
+ /// Gets or sets whether the clock pointer is currently being dragged.
+ ///
public bool PointerMoving { get; set; }
+ ///
+ /// Gets the element reference for the clock surface.
+ ///
protected ElementReference ClockElementReference { get; private set; }
private bool _amPm = false;
@@ -85,6 +102,9 @@ private void SyncTimeFromValue()
_timeSet.Minute = _workingValue.Value.Minute;
}
+ ///
+ /// The active picker mode.
+ ///
protected PickerMode _mode = PickerMode.Date;
///
@@ -110,9 +130,9 @@ public T? Value
/// Shows a 12-hour selection clock.
///
///
- /// Defaults to false.
- /// When true, hours 1-12 are displayed with an AM or PM marker.
- /// When false, hours 0-23 are displayed.
+ /// Defaults to false.
+ /// When true, hours 1-12 are displayed with an AM or PM marker.
+ /// When false, hours 0-23 are displayed.
///
[Parameter]
public bool AmPm
@@ -176,6 +196,7 @@ private int RoundToStepInterval(int value)
[Parameter]
public string PmText { get; set; } = "PM";
+ ///
protected override async Task WriteTextAsync(string? text)
{
if (string.IsNullOrWhiteSpace(text))
@@ -230,6 +251,12 @@ private async Task OnPmClickedAsync()
private DateTimeOffset _lastSetTime = DateTimeOffset.MinValue;
private const int DebounceTimeoutMs = 100;
+ ///
+ /// Sets the selected date and optionally updates the input text and bound value.
+ ///
+ /// The date to set, or to clear the selection.
+ /// Whether to update the displayed text and reset conversion errors.
+ /// A task that represents the asynchronous operation.
protected internal async Task SetDateAsync(DateTime? date, bool updateValue)
{
var current = ToDateTime(_value);
@@ -326,6 +353,7 @@ private void SetTimePart(int hour, int minute)
);
}
+ ///
protected override string GetDayClasses(int month, DateTime day)
{
var b = new CssBuilder("mud-day");
@@ -399,7 +427,7 @@ protected override async Task SubmitAsync()
}
///
- /// Clears the selected date and time, resetting the component to its initial state. If is true, the picker will also close after clearing the value.
+ /// Clears the selected date and time, resetting the component to its initial state. If AutoClose is true, the picker will also close after clearing the value.
///
/// Indicates whether the picker should close after clearing the value.
/// A task that represents the asynchronous operation.
@@ -417,13 +445,28 @@ public override async Task ClearAsync(bool close = true)
/// The formatted date string for the title of the picker.
protected string GetTitleDateString()
{
- var date = _workingValue
- ?? ToDateTime(Value)
- ?? TimeProvider.GetLocalNow().Date;
+ var date = GetPickerHeaderDate(_workingValue ?? ToDateTime(Value));
return FormatTitleDate(date);
}
+ ///
+ /// Gets the date used in the picker header.
+ ///
+ ///
+ /// A non-nullable date picker uses its default value as its cleared value. The header uses the current local date
+ /// as the picker reference date for that sentinel instead of presenting it as a selected value.
+ ///
+ private DateTime GetPickerHeaderDate(DateTime? date)
+ {
+ var boundDate = ToDateTime(_value);
+
+ if (date is not null && (!IsDefaultValue(_value) || date != boundDate))
+ return date.Value;
+
+ return TimeProvider.GetLocalNow().Date;
+ }
+
///
/// Calculates the first day of the month for the current calendar context.
///
@@ -454,18 +497,31 @@ protected override int GetCalendarYear(DateTime yearDate)
return GetCulture().Calendar.GetYear(date) - diff;
}
+ ///
+ /// Gets the localized name of a displayed month.
+ ///
+ /// The zero-based offset from the displayed month.
+ /// The localized month name and year.
protected string GetMonthName(int month)
{
var date = GetMonthStart(month);
return date.ToString("MMMM yyyy", GetCulture());
}
+ ///
+ /// Moves the calendar to the previous month.
+ ///
+ /// A completed task.
protected Task OnPreviousMonthClick()
{
PickerMonth = GetMonthStart(0).AddMonths(-1);
return Task.CompletedTask;
}
+ ///
+ /// Moves the calendar to the next month.
+ ///
+ /// A completed task.
protected Task OnNextMonthClick()
{
PickerMonth = GetMonthStart(0).AddMonths(1);
@@ -489,16 +545,29 @@ private void OnYearClick()
}
}
+ ///
+ /// Gets the earliest selectable year.
+ ///
+ /// The year from MinDate, or 1900 when no minimum is set.
protected int GetMinYear()
{
return MinDate?.Year ?? 1900;
}
+ ///
+ /// Gets the latest selectable year.
+ ///
+ /// The year from MaxDate, or 2100 when no maximum is set.
protected int GetMaxYear()
{
return MaxDate?.Year ?? 2100;
}
+ ///
+ /// Handles selection of a year in the calendar.
+ ///
+ /// The selected year.
+ /// A task that represents the asynchronous operation.
protected Task OnYearClickedAsync(int year)
{
var current = ToDateTime(Value) ?? TimeProvider.GetLocalNow().Date;
@@ -517,12 +586,22 @@ protected Task OnYearClickedAsync(int year)
return Task.CompletedTask;
}
+ ///
+ /// Gets the typography style for a year.
+ ///
+ /// The year to evaluate.
+ /// The typography style for the year.
protected Typo GetYearTypo(int year)
{
var current = ToDateTime(Value);
return current?.Year == year ? Typo.h5 : Typo.body1;
}
+ ///
+ /// Gets the CSS classes for a year.
+ ///
+ /// The year to evaluate.
+ /// The CSS classes for the year.
protected string GetYearClasses(int year)
{
var current = ToDateTime(Value);
@@ -532,23 +611,40 @@ protected string GetYearClasses(int year)
.Build();
}
+ ///
+ /// Moves the calendar to the previous year.
+ ///
+ /// A completed task.
protected Task OnPreviousYearClick()
{
PickerMonth = (PickerMonth ?? DateTime.Today).AddYears(-1);
return Task.CompletedTask;
}
+ ///
+ /// Moves the calendar to the next year.
+ ///
+ /// A completed task.
protected Task OnNextYearClick()
{
PickerMonth = (PickerMonth ?? DateTime.Today).AddYears(1);
return Task.CompletedTask;
}
+ ///
+ /// Gets all month numbers used by the month-selection view.
+ ///
+ /// The month numbers from 1 through 12.
protected IEnumerable GetAllMonths()
{
return Enumerable.Range(1, 12);
}
+ ///
+ /// Handles selection of a month in the calendar.
+ ///
+ /// The selected month number.
+ /// A task that represents the asynchronous operation.
protected Task OnMonthSelectedAsync(int month)
{
var current = _workingValue ?? ToDateTime(Value) ?? TimeProvider.GetLocalNow().Date;
@@ -567,6 +663,11 @@ protected Task OnMonthSelectedAsync(int month)
return Task.CompletedTask;
}
+ ///
+ /// Determines whether every day in a month is outside the configured date range.
+ ///
+ /// The month number to evaluate.
+ /// when the month is disabled; otherwise, .
protected bool IsMonthDisabled(int month)
{
if (!MinDate.HasValue && !MaxDate.HasValue)
@@ -581,12 +682,22 @@ protected bool IsMonthDisabled(int month)
|| (MaxDate.HasValue && start > MaxDate.Value);
}
+ ///
+ /// Gets the typography style for a month.
+ ///
+ /// The month number to evaluate.
+ /// The typography style for the month.
protected Typo GetMonthTypo(int month)
{
var current = ToDateTime(Value);
return current?.Month == month ? Typo.h6 : Typo.body2;
}
+ ///
+ /// Gets the CSS classes for a month.
+ ///
+ /// The month number to evaluate.
+ /// The CSS classes for the month.
protected string GetMonthClasses(int month)
{
var current = ToDateTime(Value);
@@ -596,11 +707,22 @@ protected string GetMonthClasses(int month)
.Build();
}
+ ///
+ /// Gets the localized abbreviated name of a month.
+ ///
+ /// The month number.
+ /// The abbreviated month name.
protected string GetAbbreviatedMonthName(int month)
{
return GetCulture().DateTimeFormat.AbbreviatedMonthNames[month - 1];
}
+ ///
+ /// Gets the culture-specific week number for a displayed calendar week.
+ ///
+ /// The zero-based offset from the displayed month.
+ /// The zero-based week index.
+ /// The week number.
protected int GetWeekNumber(int month, int week)
{
var firstDay = GetWeek(month, week).First();
@@ -611,16 +733,28 @@ protected int GetWeekNumber(int month, int week)
GetFirstDayOfWeek());
}
+ ///
+ /// Gets the day-of-month text for a calendar date.
+ ///
+ /// The date to format.
+ /// The localized day-of-month text.
protected string GetCalendarDayOfMonth(DateTime date)
{
return date.Day.ToString(GetCulture());
}
+ ///
+ /// Switches the picker to month selection.
+ ///
protected void OnFormattedDateClick()
{
CurrentView = OpenTo.Month;
}
+ ///
+ /// Switches the picker to month selection.
+ ///
+ /// The clicked month number.
protected void OnMonthClicked(int month)
{
CurrentView = OpenTo.Month;
@@ -750,6 +884,12 @@ private static string GetTransform(double angle, double radius, double offsetX,
return $"transform: translate({x}px, {y}px);";
}
+ ///
+ /// Updates the working time from a clock-pointer movement.
+ ///
+ /// The hour or minute indicated by the clock pointer.
+ /// Whether the pointer is currently being dragged.
+ /// A task that represents the asynchronous operation.
[JSInvokable]
public async Task SelectTimeFromStick(int value, bool pointerMoving)
{
@@ -765,6 +905,11 @@ public async Task SelectTimeFromStick(int value, bool pointerMoving)
StateHasChanged();
}
+ ///
+ /// Handles a click on the clock pointer and advances or submits the time selection.
+ ///
+ /// The selected hour or minute.
+ /// A task that represents the asynchronous operation.
[JSInvokable]
public async Task OnStickClick(int value)
{
@@ -792,6 +937,10 @@ public async Task OnStickClick(int value)
StateHasChanged();
}
+ ///
+ /// Submits the working value and closes the picker when its configuration permits it.
+ ///
+ /// A task that represents the asynchronous operation.
protected async Task SubmitAndCloseAsync()
{
if (PickerActions == null || AutoClose)
@@ -871,11 +1020,13 @@ private void HandleModeChange(PickerMode mode)
}
}
+ ///
+ /// Gets the year displayed in the picker toolbar.
+ ///
+ /// The formatted year.
protected string GetFormattedYearString()
{
- var date = _workingValue
- ?? ToDateTime(Value)
- ?? TimeProvider.GetLocalNow().Date;
+ var date = GetPickerHeaderDate(_workingValue ?? ToDateTime(Value));
return date.Year.ToString();
}
@@ -903,6 +1054,7 @@ public override async Task ScrollToYearAsync(DateTime? date = null)
StateHasChanged();
}
+ ///
protected override async Task OnOpenedAsync()
{
_mode = PickerMode.Date;
diff --git a/tests/CodeBeam.MudBlazor.Extensions.UnitTests/Components/DateTimePickerTests.cs b/tests/CodeBeam.MudBlazor.Extensions.UnitTests/Components/DateTimePickerTests.cs
index 0fec0d9d..e740b0e1 100644
--- a/tests/CodeBeam.MudBlazor.Extensions.UnitTests/Components/DateTimePickerTests.cs
+++ b/tests/CodeBeam.MudBlazor.Extensions.UnitTests/Components/DateTimePickerTests.cs
@@ -2,6 +2,8 @@
using Bunit;
using Microsoft.AspNetCore.Components;
+using System.Reflection;
+
namespace MudExtensions.UnitTests.Components;
[TestFixture]
@@ -98,4 +100,49 @@ public void DateTimePicker_Null_Value_Should_Render_Empty()
var comp = RenderPicker();
comp.Find("input").GetAttribute("value").Should().BeNullOrEmpty();
}
+
+ [Test]
+ public async Task DateTimePicker_DefaultDateTime_Should_Open_Current_Month()
+ {
+ await AssertDefaultValueOpensCurrentMonthAsync();
+ }
+
+ [Test]
+ public async Task DateTimePicker_DefaultDateOnly_Should_Open_Current_Month()
+ {
+ await AssertDefaultValueOpensCurrentMonthAsync();
+ }
+
+ [Test]
+ public async Task DateTimePicker_DefaultDateTimeOffset_WithIstanbulTimeZone_Should_Open_Current_Month()
+ {
+ var istanbulTimeZone = TimeZoneInfo.FindSystemTimeZoneById("Europe/Istanbul");
+ await AssertDefaultValueOpensCurrentMonthAsync(istanbulTimeZone);
+ }
+
+ private async Task AssertDefaultValueOpensCurrentMonthAsync(TimeZoneInfo? timeZone = null)
+ {
+ var today = DateTime.Today;
+ var expectedMonth = new DateTime(today.Year, today.Month, 1);
+ var comp = Context.Render>(parameters =>
+ {
+ parameters.Add(p => p.Value, default(T));
+
+ if (timeZone is not null)
+ parameters.Add(p => p.TimeZone, timeZone);
+ });
+
+ await InvokePickerOpenedAsync(comp.Instance);
+
+ comp.Instance.PickerMonth.Should().Be(expectedMonth);
+ }
+
+ private static Task InvokePickerOpenedAsync(MudDateTimePicker picker)
+ {
+ var method = typeof(MudBaseDatePickerX).GetMethod(
+ "OnPickerOpenedAsync",
+ BindingFlags.Instance | BindingFlags.NonPublic);
+
+ return (Task)method!.Invoke(picker, null)!;
+ }
}