Skip to content
Closed
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<FluentStack Wrap="true" HorizontalGap="24px">

<div>
<FluentCalendar DisabledDateFunc="@DisabledDay"
@bind-Value="@SelectedDay"
@bind-PickerMonth="@PickerDay"
MinDate="@StartOfMonth"
MaxDate="@EndOfMonth"
Style="height: 250px; align-content: start;" />
<p>Selected @(SelectedDay.ToString("yyyy-MM-dd"))</p>
<p>Panel @(PickerDay.ToString("yyyy-MM-dd"))</p>
</div>

<div>
<FluentCalendar View="CalendarViews.Months"
@bind-Value="@SelectedMonth"
@bind-PickerMonth="@PickerMonth"
MinDate="@(new DateTime(2026, 3, 1))"
MaxDate="@(new DateTime(Today.Year+1, 7, 30))"
Style="height: 250px; align-content: start;" />
<p>Selected @(SelectedMonth.ToString("yyyy-MM-dd"))</p>
<p>Panel @(PickerMonth.ToString("yyyy-MM-dd"))</p>
</div>

<div>
<FluentCalendar View="CalendarViews.Years"
@bind-Value="@SelectedYear"
@bind-PickerMonth="@PickerYear"
MaxDate="@(new DateTime(2030, 7, 30))"
Style="height: 250px; align-content: start;" />
<p>Selected @(SelectedYear.ToString("yyyy-MM-dd"))</p>
<p>Panel @(PickerYear.ToString("yyyy-MM-dd"))</p>
</div>
</FluentStack>

@code
{
private static readonly DateTime Today = DateTime.Today;
private static readonly DateTime StartOfMonth = new DateTime(Today.Year, Today.Month, 1);
private static readonly DateTime EndOfMonth = new DateTime(Today.Year, Today.Month, DateTime.DaysInMonth(Today.Year, Today.Month));

private DateTime SelectedDay = Today;
private DateTime PickerDay = StartOfMonth;
private DateTime SelectedMonth = Today;
private DateTime PickerMonth = StartOfMonth;
private DateTime SelectedYear = Today;
private DateTime PickerYear = StartOfMonth;

private bool DisabledDay(DateTime date) => date.Day == 3 || date.Day == 8 || date.Day == 20;

}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,18 @@ The user can switch between these views using the title item: the month name or

{{ CalendarDefault }}

## Setting a minimum and maximum date

You can set a minimum and maximum date for the calendar using the `MinDate` and `MaxDate` parameters.

In the first example below, the view is bound to the current month, and the user can only select dates within the current month.

In the second example, both `MinDate` and `MaxDate` are set so only months within that period can be selected

In the third example, only a `MaxDate` is set to limit the year selection to a specific range of years.

{{ CalendarMinMax }}

## Selections

You can activate the selection mode by setting the `SelectMode` parameter
Expand Down
90 changes: 78 additions & 12 deletions src/Core/Components/DateTime/CalendarTitles.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
// This file is licensed to you under the MIT License.
// ------------------------------------------------------------------------

using Microsoft.FluentUI.AspNetCore.Components.Extensions;

namespace Microsoft.FluentUI.AspNetCore.Components.Calendar;

/// <summary>
Expand Down Expand Up @@ -55,7 +57,7 @@ public bool ReadOnly
CalendarViews.Days => false,
CalendarViews.Months => false,
CalendarViews.Years => true,
_ => true
_ => true,
};
}
}
Expand All @@ -74,7 +76,7 @@ public string Label
CalendarViews.Months => CalendarExtended.GetYear(),
CalendarViews.Years => CalendarExtended.GetYearsRangeLabel(Date.GetYear(_calendar.Culture) - CalendarExtended.YearShiftCentered),
#pragma warning restore MA0011
_ => string.Empty
_ => string.Empty,
};
}
}
Expand All @@ -91,7 +93,7 @@ public string PreviousTitle
CalendarViews.Days => CalendarExtended.GetMonthName(Date.AddMonths(-1, _calendar.Culture)),
CalendarViews.Months => CalendarExtended.GetYear(Date.AddYears(-1, _calendar.Culture)),
CalendarViews.Years => CalendarExtended.GetYearsRangeLabel(Date.GetYear(_calendar.Culture) - 12 - CalendarExtended.YearShiftCentered),
_ => string.Empty
_ => string.Empty,
};
}
}
Expand All @@ -107,12 +109,47 @@ public bool PreviousDisabled
var minDate = _calendar.Culture.Calendar.MinSupportedDateTime.AddMonths(1);
#pragma warning restore MA0011

var rangeMinDate = _calendar.MinDate.ConvertToDateTime()?.Date;
var rangePreviousDisabled = false;
if (rangeMinDate.HasValue)
{
var candidate = View switch
{
CalendarViews.Days => Date.AddMonths(-1, _calendar.Culture),
CalendarViews.Months => Date.AddYears(-1, _calendar.Culture),
CalendarViews.Years => Date.AddYears(-12, _calendar.Culture),
_ => Date,
};

var candidatePeriodEnd = View switch
{
CalendarViews.Days
=> candidate.StartOfMonth(_calendar.Culture)
.AddMonths(1, _calendar.Culture)
.AddDays(-1),

CalendarViews.Months
=> candidate.StartOfYear(_calendar.Culture)
.AddYears(1, _calendar.Culture)
.AddDays(-1),

CalendarViews.Years
=> candidate.StartOfYear(_calendar.Culture)
.AddYears(12, _calendar.Culture)
.AddDays(-1),

_ => candidate,
};

rangePreviousDisabled = candidatePeriodEnd.Date < rangeMinDate.Value;
}

return View switch
{
CalendarViews.Days => Date.Year == minDate.Year && Date.Month == minDate.Month,
CalendarViews.Months => Date.Year == minDate.Year,
CalendarViews.Years => Date.Year - CalendarExtended.YearShiftCentered <= minDate.Year + 12,
_ => false
CalendarViews.Days => (Date.Year == minDate.Year && Date.Month == minDate.Month) || rangePreviousDisabled,
CalendarViews.Months => Date.Year == minDate.Year || rangePreviousDisabled,
CalendarViews.Years => Date.Year - CalendarExtended.YearShiftCentered <= minDate.Year + 12 || rangePreviousDisabled,
_ => false,
};
}
}
Expand All @@ -129,7 +166,7 @@ public string NextTitle
CalendarViews.Days => CalendarExtended.GetMonthName(Date.AddMonths(+1, _calendar.Culture)),
CalendarViews.Months => CalendarExtended.GetYear(Date.AddYears(+1, _calendar.Culture)),
CalendarViews.Years => CalendarExtended.GetYearsRangeLabel(Date.GetYear(_calendar.Culture) + 12 - CalendarExtended.YearShiftCentered),
_ => string.Empty
_ => string.Empty,
};
}
}
Expand All @@ -143,12 +180,41 @@ public bool NextDisabled
{
var maxDate = _calendar.Culture.Calendar.MaxSupportedDateTime;

var rangeMaxDate = _calendar.MaxDate.ConvertToDateTime()?.Date;
var rangeNextDisabled = false;
if (rangeMaxDate.HasValue)
{
var candidate = View switch
{
CalendarViews.Days => Date.AddMonths(+1, _calendar.Culture),
CalendarViews.Months => Date.AddYears(+1, _calendar.Culture),
CalendarViews.Years => Date.AddYears(+12, _calendar.Culture),
_ => Date,
};

var candidatePeriodStart = View switch
{
CalendarViews.Days
=> candidate.StartOfMonth(_calendar.Culture),

CalendarViews.Months
=> candidate.StartOfYear(_calendar.Culture),

CalendarViews.Years
=> candidate.StartOfYear(_calendar.Culture),

_ => candidate,
};

rangeNextDisabled = candidatePeriodStart.Date > rangeMaxDate.Value;
}

return View switch
{
CalendarViews.Days => Date.Year == maxDate.Year && Date.Month == maxDate.Month,
CalendarViews.Months => Date.Year == maxDate.Year,
CalendarViews.Years => Date.Year + 12 - CalendarExtended.YearShiftCentered >= maxDate.Year,
_ => false
CalendarViews.Days => (Date.Year == maxDate.Year && Date.Month == maxDate.Month) || rangeNextDisabled,
CalendarViews.Months => Date.Year == maxDate.Year || rangeNextDisabled,
CalendarViews.Years => Date.Year + 12 - CalendarExtended.YearShiftCentered >= maxDate.Year || rangeNextDisabled,
_ => false,
};
}
}
Expand Down
5 changes: 5 additions & 0 deletions src/Core/Components/DateTime/FluentCalendar.razor
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@

@* Title bar (label, previous and next buttons) *@
<div class="title" part="title" aria-label="@titles.Label">

<div part="label" class="@GetAnimationClass("label")" readonly="@ReadOnly"
role="button" tabindex="0"
@onclick="@(e => TitleClickHandlerAsync(titles))">
Expand Down Expand Up @@ -177,6 +178,8 @@
ValueChanged="@PickerMonthSelectAsync"
ReadOnly="@ReadOnly"
Disabled="@Disabled"
MinDate="@(MinDate.ConvertToDateTime() ?? default)"
MaxDate="@(MaxDate.ConvertToDateTime() ?? default)"
Culture="@Culture"
DisabledSelectable="@DisabledSelectable"
AnimatePeriodChanges="@AnimatePeriodChanges"
Expand All @@ -193,6 +196,8 @@
ValueChanged="@PickerYearSelectAsync"
ReadOnly="@ReadOnly"
Disabled="@Disabled"
MinDate="@(MinDate.ConvertToDateTime() ?? default)"
MaxDate="@(MaxDate.ConvertToDateTime() ?? default)"
Culture="@Culture"
DisabledSelectable="@DisabledSelectable"
AnimatePeriodChanges="@AnimatePeriodChanges"
Expand Down
Loading
Loading