Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
@page "/muddatetimepicker"
@namespace MudExtensions.Docs.Pages

<ExamplePage Component="typeof(MudDateTimePicker<>)">
<ExampleCard ComponentName="DateTimePicker" ExampleName="DateTimePickerExample1" Title="Usage" Description="MudDateTimePicker automatically converts wheel values to DateTime?.">
<DateTimePickerExample1 />
</ExampleCard>
<ExampleCard ComponentName="DateTimePicker" ExampleName="DateTimePickerExample2" Title="MinDate & MaxDate" Description="You can restrict available date with MinDate and MaxDate parameters.">
<DateTimePickerExample2 />
</ExampleCard>
</ExamplePage>
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
@namespace MudExtensions.Docs.Examples
@using MudBlazor.Extensions

<MudGrid>
<MudItem xs="12" sm="8">
<MudDateTimePicker @bind-Value="_date" Editable="_editable" Label="Date" Clearable="_clearable"
ShowToolbar="_showToolbar" Variant="_variant" Color="_color"
Format="@_dateFormat"
TransformOrigin="Origin.TopCenter" AnchorOrigin="Origin.BottomCenter" />
</MudItem>

<MudItem xs="12" sm="4">
<MudStack Spacing="4">
<MudSelect @bind-Value="_dateView" Variant="Variant.Outlined" Label="Date View">
@foreach (DateView item in Enum.GetValues<DateView>())
{
<MudSelectItem Value="item">@item.ToDescriptionString()</MudSelectItem>
}
</MudSelect>
<MudSelect @bind-Value="_variant" Variant="Variant.Outlined" Label="Variant">
@foreach (Variant item in Enum.GetValues<Variant>())
{
<MudSelectItem Value="item">@item.ToDescriptionString()</MudSelectItem>
}
</MudSelect>
<MudSwitchM3 @bind-Value="_editable" Color="Color.Secondary" Label="Editable" />
<MudSwitchM3 @bind-Value="_showToolbar" Color="Color.Secondary" Label="Show Toolbar" />
<MudSwitchM3 @bind-Value="_showHeader" Color="Color.Secondary" Label="Show Header" />
<MudSwitchM3 @bind-Value="_submitOnClose" Color="Color.Secondary" Label="Submit On Close" />
<MudSwitchM3 @bind-Value="_isAdornmentEnd" Label="Adornment End" Color="Color.Secondary" />
<MudSelect @bind-Value="_color" Variant="Variant.Outlined" Label="Color">
@foreach (Color item in Enum.GetValues<Color>())
{
<MudSelectItem Value="item">@item.ToDescriptionString()</MudSelectItem>
}
</MudSelect>
<MudTextField @bind-Value="_dateFormat" Variant="Variant.Outlined" Label="Date Format" />
<MudButton OnClick="@(() => _date = DateTime.Now)">Set Today</MudButton>
</MudStack>
</MudItem>
</MudGrid>

@code {
private DateTime? _date = DateTime.Now;
private DateView _dateView = DateView.Date;
private bool _editable = false;
private bool _showToolbar = true;
private bool _showHeader = true;
private bool _submitOnClose = true;
private Color _color = Color.Primary;
private string? _dateFormat;
private bool _isAdornmentEnd = true;
private bool _clearable = false;
private Variant _variant = Variant.Outlined;
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
<MudSelectExtended T="string" Label="Data Based" ItemCollection="_collection" Disabled="_disabled" Modal="@_modal" />
<MudSelectExtended T="string" Label="Data Based" ItemCollection="_collection" Disabled="_disabled" Modal="@_modal" AddNullItem="true" AddedNullItemText="@_nullItemText" />
</MudStack>

<MudDateTimePicker T="DateTimeOffset" @bind-Value="_selectedDate" />
</MudItem>

<MudItem xs="12" sm="4">
Expand All @@ -28,4 +30,6 @@
private bool _modal = true;
private string[] _collection = new string[] { "Foo", "Bar", "Fizz", "Buzz" };
private string? _nullItemText = "None";

private DateTimeOffset _selectedDate = DateTimeOffset.Now;
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ public class MudExtensionsDocsService
new MudExtensionComponentInfo() {Title = "MudComboBox", Component = typeof(MudComboBox<>), RelatedComponents = new List<Type>() {typeof(MudComboBoxItem<string>)}, Usage = ComponentUsage.Input, IsUnique = true, Description = "Unites MudSelect and MudAutocomplete features."},
new MudExtensionComponentInfo() {Title = "MudCssManager", Component = typeof(MudCssManager), Usage = ComponentUsage.Utility, IsUnique = true, IsUtility = true, Description = "Directly and dynamically get or set component's css property."},
new MudExtensionComponentInfo() {Title = "MudCsvMapper", Component = typeof(MudCsvMapper), Usage = ComponentUsage.Display, IsUnique = true, Description = "A .csv file uploader that matches the .csv file headers to supplied / expected headers."},
new MudExtensionComponentInfo() {Title = "MudDateTimePicker", Component = typeof(MudDateTimePicker<>), Usage = ComponentUsage.Input, IsUnique = true, Description = "Unified generic date and time picker component."},
new MudExtensionComponentInfo() {Title = "MudDateWheelPicker", Component = typeof(MudDateWheelPicker), Usage = ComponentUsage.Input, IsUnique = true, Description = "A date time picker with MudWheels."},
new MudExtensionComponentInfo() {Title = "MudGallery", Component = typeof(MudGallery), Usage = ComponentUsage.Display, IsUnique = true, Description = "Mobile friendly image gallery component."},
new MudExtensionComponentInfo() {Title = "MudInputStyler", Component = typeof(MudInputStyler), Usage = ComponentUsage.Utility, IsUnique = true, Description = "Applies colors or other CSS styles easily for mud inputs like MudTextField and MudSelect."},
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,261 @@
using Microsoft.AspNetCore.Components;
using MudBlazor;
using MudBlazor.Extensions;
using MudBlazor.State;
using MudBlazor.Utilities;
using System.Globalization;
using System.Runtime.Serialization;

namespace MudExtensions
{
public abstract partial class MudBaseDatePickerX<T> : MudPicker<T>
{
internal readonly string _mudPickerCalendarContentElementId;
private readonly ParameterState<string?> _formatState;

protected MudBaseDatePickerX()
{
_mudPickerCalendarContentElementId = Identifier.Create();
Culture = CultureInfo.CurrentCulture;

using var registerScope = CreateRegisterScope();
_formatState = registerScope.RegisterParameter<string?>(nameof(Format))
.WithParameter(() => Format)
.WithChangeHandler(FormatChangedAsync);
}

// 🔥 GENERIC CONVERSION LAYER
protected DateTime? ToDateTime(T? value)
{
if (value == null)
return null;

if (value is DateTime dt)
return dt;

if (value is DateTimeOffset dto)
return dto.LocalDateTime;

throw new NotSupportedException($"Type {typeof(T)} not supported");
}

protected T? FromDateTime(DateTime? date)
{
if (date == null)
return default;

var t = Nullable.GetUnderlyingType(typeof(T)) ?? typeof(T);

if (t == typeof(DateTime))
return (T)(object)date.Value;

if (t == typeof(DateTimeOffset))
{
var offset = TimeZoneInfo.Local.GetUtcOffset(date.Value);
return (T)(object)new DateTimeOffset(date.Value, offset);
}

throw new NotSupportedException($"Type {typeof(T)} not supported");
}

protected void ValidateType()
{
var t = Nullable.GetUnderlyingType(typeof(T)) ?? typeof(T);

if (t != typeof(DateTime) && t != typeof(DateTimeOffset))
throw new NotSupportedException($"Type {typeof(T)} not supported.");
}

protected override void OnInitialized()
{
ValidateType();
base.OnInitialized();
}

[Inject] protected IScrollManager ScrollManager { get; set; } = null!;
[Inject] private IJsApiService JsApiService { get; set; } = null!;
[Inject] protected TimeProvider TimeProvider { get; set; } = null!;

[Parameter] public DateTime? MaxDate { get; set; }
[Parameter] public DateTime? MinDate { get; set; }
[Parameter] public OpenTo OpenTo { get; set; } = OpenTo.Date;

[Parameter, ParameterState]
public string? Format { get; set; }

protected virtual Task FormatChangedAsync(string? newFormat) => Task.CompletedTask;

private Task FormatChangedAsync(ParameterChangedEventArgs<string?> args)
=> FormatChangedAsync(args.Value);

[Parameter] public DayOfWeek? FirstDayOfWeek { get; set; }

internal DateTime? _picker_month;

[Parameter]
public DateTime? PickerMonth
{
get => _picker_month;
set
{
if (value == _picker_month)
return;
_picker_month = value;
InvokeAsync(StateHasChanged);
PickerMonthChanged.InvokeAsync(value);
}
}

protected internal DateTime? HighlightedDate { get; set; }

[Parameter] public EventCallback<DateTime?> PickerMonthChanged { get; set; }

[Parameter] public int ClosingDelay { get; set; } = 100;
[Parameter] public int DisplayMonths { get; set; } = 1;
[Parameter] public int? MaxMonthColumns { get; set; }
[Parameter] public DateTime? StartMonth { get; set; }
[Parameter] public bool ShowWeekNumbers { get; set; }
[Parameter] public string TitleDateFormat { get; set; } = "ddd, dd MMM";
[Parameter] public bool AutoClose { get; set; }

[Parameter]
public Func<DateTime, bool> IsDateDisabledFunc { get; set; } = _ => false;

[Parameter] public Func<DateTime, string>? AdditionalDateClassesFunc { get; set; }
[Parameter] public string PreviousIcon { get; set; } = Icons.Material.Filled.ChevronLeft;
[Parameter] public string NextIcon { get; set; } = Icons.Material.Filled.ChevronRight;

[Parameter] public int? FixYear { get; set; }
[Parameter] public int? FixMonth { get; set; }
[Parameter] public int? FixDay { get; set; }

protected OpenTo CurrentView;

protected override async Task OnPickerOpenedAsync()
{
await base.OnPickerOpenedAsync();

var dateTime = ToDateTime(_value);

if (dateTime.HasValue)
{
var culture = GetCulture();
var calendar = culture.Calendar;
PickerMonth = new DateTime(
calendar.GetYear(dateTime.Value),
calendar.GetMonth(dateTime.Value),
1,
calendar);
}

CurrentView = OpenTo;
}

protected DateTime GetMonthStart(int month)
{
var culture = GetCulture();
var calendar = culture.Calendar;
var baseDate = _picker_month ?? DateTime.Today;

return calendar.AddMonths(new DateTime(baseDate.Year, baseDate.Month, 1), month);
}

protected IEnumerable<DateTime> GetWeek(int month, int index)
{
if (index is < 0 or > 5)
throw new ArgumentException("Index must be between 0 and 5", nameof(index));

var culture = GetCulture();
var monthFirst = GetMonthStart(month);

var weekFirst = monthFirst
.AddDays(index * 7)
.StartOfWeek(GetFirstDayOfWeek(), culture);

for (var i = 0; i < 7; i++)
yield return weekFirst.AddDays(i);
}

protected virtual bool IsDayDisabled(DateTime date)
{
return date < MinDate ||
date > MaxDate ||
IsDateDisabledFunc(date);
}

protected abstract string GetDayClasses(int month, DateTime day);
protected abstract Task OnDayClickedAsync(DateTime dateTime);

protected string FormatTitleDate(DateTime? date)
{
return date?.ToString(TitleDateFormat, GetCulture()) ?? "";
}

protected string GetFormattedYearString()
{
var selectedYear = HighlightedDate ?? GetMonthStart(0);
return selectedYear.Year.ToString();
}

protected IEnumerable<string> GetAbbreviatedDayNames()
{
var culture = GetCulture();
var names = culture.DateTimeFormat.AbbreviatedDayNames;

var firstDay = (int)GetFirstDayOfWeek();

return Enumerable.Range(0, 7).Select(i => names[(i + firstDay) % 7]);
}

protected override IConverter<T?, string?> GetDefaultConverter()
{
return new DefaultConverter<T?>
{
Culture = GetCulture,
Format = GetFormat
};
}

protected override string? ConvertSet(T? value)
{
var dt = ToDateTime(value);

if (dt == null)
return null;

return dt.Value.ToString(GetFormat(), GetCulture());
}

protected override string GetFormat()
{
if (!string.IsNullOrWhiteSpace(_formatState.Value))
return _formatState.Value;

return $"{CultureInfo.CurrentCulture.DateTimeFormat.ShortDatePattern} HH:mm";
}

protected abstract DateTime GetCalendarStartOfMonth();
protected abstract int GetCalendarYear(DateTime yearDate);

protected DayOfWeek GetFirstDayOfWeek()
{
return FirstDayOfWeek ?? GetCulture().DateTimeFormat.FirstDayOfWeek;
}

protected DateTime GetMonthEnd(int month)
{
var culture = GetCulture();
var calendar = culture.Calendar;
var monthStartDate = PickerMonth ?? DateTime.Today.StartOfMonth(culture);

return calendar
.AddMonths(monthStartDate, month)
.EndOfMonth(culture);
}

//private ValueTask HandleMouseoverOnPickerCalendarDayButton(int tempId)
//{
// return JsApiService.UpdateStyleProperty(_mudPickerCalendarContentElementId, "--selected-day", tempId);
//}
}
}
Loading
Loading