Skip to content

Commit

Permalink
Flatpickr support for material DateEdit and TimeEdit (#2018)
Browse files Browse the repository at this point in the history
* Implemented Flatpickr for Material and optimized DateEdit parameters

* Fixed unit tests

* Dynamic change of Min and Max values

* Fix firstDayOfWeek

* Support of DisplayFormat

* Update docs

* Update Material usage docs
  • Loading branch information
stsrki committed Mar 18, 2021
1 parent cd25d82 commit c174b5e
Show file tree
Hide file tree
Showing 18 changed files with 446 additions and 82 deletions.
1 change: 1 addition & 0 deletions Demos/Blazorise.Demo.Material/wwwroot/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

<link href="_content/Blazorise/blazorise.css" rel="stylesheet" />
<link href="_content/Blazorise.Material/blazorise.material.css" rel="stylesheet" />
<link href="_content/Blazorise.Material/blazorise.material.flatpickr.css" rel="stylesheet" />
<link href="_content/Blazorise.DataGrid/blazorise.datagrid.css" rel="stylesheet" />
<link href="_content/Blazorise.Sidebar/blazorise.sidebar.css" rel="stylesheet" />
<link href="_content/Blazorise.Snackbar/blazorise.snackbar.css" rel="stylesheet" />
Expand Down
2 changes: 2 additions & 0 deletions Source/Blazorise.Material/Config.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ public static IServiceCollection AddMaterialProviders( this IServiceCollection s
serviceCollection.AddBootstrapComponents();

// material overrides
serviceCollection.AddTransient( typeof( Blazorise.DateEdit<> ), typeof( Material.DateEdit<> ) );
serviceCollection.AddTransient( typeof( Blazorise.TimeEdit<> ), typeof( Material.TimeEdit<> ) );
serviceCollection.AddTransient( typeof( Blazorise.Switch<> ), typeof( Material.Switch<> ) );
serviceCollection.AddTransient<Blazorise.Step, Material.Step>();
serviceCollection.AddTransient<Blazorise.Steps, Material.Steps>();
Expand Down
5 changes: 5 additions & 0 deletions Source/Blazorise.Material/DateEdit.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
@typeparam TValue
@inherits Blazorise.DateEdit<TValue>
<input @ref="@ElementRef" id="@ElementId" type="text" class="@ClassNames" style="@StyleNames" disabled="@Disabled" readonly="@ReadOnly" pattern="@Pattern" value="@CurrentValueAsString" @onchange="@OnChangeHandler" @onclick="@OnClickHandler" placeholder="@Placeholder" min="@Min?.ToString(Utilities.Parsers.InternalDateFormat)" max="@Max?.ToString(Utilities.Parsers.InternalDateFormat)" tabindex="@TabIndex" @onkeydown="@OnKeyDownHandler" @onkeypress="@OnKeyPressHandler" @onkeyup="@OnKeyUpHandler" @onblur="@OnBlurHandler" @onfocus="@OnFocusHandler" @onfocusin="@OnFocusInHandler" @onfocusout="@OnFocusOutHandler" @attributes="@Attributes" />
@ChildContent
@Feedback
39 changes: 37 additions & 2 deletions Source/Blazorise.Material/MaterialJSRunner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,44 @@ public override ValueTask<bool> InitializeTooltip( ElementReference elementRef,
return runtime.InvokeAsync<bool>( $"blazoriseMaterial.tooltip.initialize", elementRef, elementId );
}

public override ValueTask<bool> ActivateDatePicker( string elementId, string formatSubmit )
public override ValueTask InitializeDatePicker( ElementReference elementRef, string elementId, object options )
{
return runtime.InvokeAsync<bool>( $"blazoriseMaterial.activateDatePicker", elementId, formatSubmit );
return runtime.InvokeVoidAsync( $"blazoriseMaterial.dateEdit.initialize", elementRef, elementId, options );
}

public override ValueTask DestroyDatePicker( ElementReference elementRef, string elementId )
{
return runtime.InvokeVoidAsync( $"blazoriseMaterial.dateEdit.destroy", elementRef, elementId );
}

public override ValueTask UpdateDatePickerValue( ElementReference elementRef, string elementId, object value )
{
return runtime.InvokeVoidAsync( $"blazoriseMaterial.dateEdit.update", elementRef, elementId, value );
}

public override ValueTask UpdateDatePickerOptions( ElementReference elementRef, string elementId, object options )
{
return runtime.InvokeVoidAsync( $"blazoriseMaterial.dateEdit.updateOptions", elementRef, elementId, options );
}

public override ValueTask InitializeTimePicker( ElementReference elementRef, string elementId, object options )
{
return runtime.InvokeVoidAsync( $"blazoriseMaterial.timeEdit.initialize", elementRef, elementId, options );
}

public override ValueTask DestroyTimePicker( ElementReference elementRef, string elementId )
{
return runtime.InvokeVoidAsync( $"blazoriseMaterial.timeEdit.destroy", elementRef, elementId );
}

public override ValueTask UpdateTimePickerValue( ElementReference elementRef, string elementId, object value )
{
return runtime.InvokeVoidAsync( $"blazoriseMaterial.timeEdit.updateValue", elementRef, elementId, value );
}

public override ValueTask UpdateTimePickerOptions( ElementReference elementRef, string elementId, object options )
{
return runtime.InvokeVoidAsync( $"blazoriseMaterial.timeEdit.updateOptions", elementRef, elementId, options );
}

public override ValueTask<bool> OpenModal( ElementReference elementRef, bool scrollToTop )
Expand Down
21 changes: 21 additions & 0 deletions Source/Blazorise.Material/MaterialThemeGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,27 @@ protected override void GenerateButtonOutlineVariantStyles( StringBuilder sb, Th
.AppendLine( "}" );
}

protected override void GenerateInputStyles( StringBuilder sb, Theme theme, ThemeInputOptions options )
{
sb
.Append( $".flatpickr-day.selected" ).Append( "{" )
.Append( $"background: { Var( ThemeVariables.Color( "primary" ) )};" )
.AppendLine( "}" );

sb
.Append( $".flatpickr-time .flatpickr-am-pm" ).Append( "{" )
.Append( $"color: { Var( ThemeVariables.Color( "primary" ) )};" )
.AppendLine( "}" );

sb
.Append( $".flatpickr-time .flatpickr-am-pm:focus, .flatpickr-time input:focus" ).Append( "{" )
.Append( $"background: { ToHex( Transparency( Var( ThemeVariables.Color( "primary" ) ), 16 ) )};" )
.Append( $"color: { Var( ThemeVariables.Color( "primary" ) )};" )
.AppendLine( "}" );

base.GenerateInputStyles( sb, theme, options );
}

protected override void GenerateInputCheckEditStyles( StringBuilder sb, Theme theme, ThemeInputOptions options )
{
sb
Expand Down
5 changes: 5 additions & 0 deletions Source/Blazorise.Material/TimeEdit.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
@typeparam TValue
@inherits Blazorise.TimeEdit<TValue>
<input @ref="@ElementRef" id="@ElementId" type="text" class="@ClassNames" style="@StyleNames" disabled="@Disabled" readonly="@ReadOnly" pattern="@Pattern" value="@CurrentValueAsString" tabindex="@TabIndex" @onchange="@OnChangeHandler" @onclick="@OnClickHandler" placeholder="@Placeholder" @onkeydown="@OnKeyDownHandler" @onkeypress="@OnKeyPressHandler" @onkeyup="@OnKeyUpHandler" @onblur="@OnBlurHandler" @onfocus="@OnFocusHandler" @onfocusin="@OnFocusInHandler" @onfocusout="@OnFocusOutHandler" @attributes="@Attributes" />
@ChildContent
@Feedback

Large diffs are not rendered by default.

138 changes: 109 additions & 29 deletions Source/Blazorise.Material/wwwroot/blazorise.material.js

Large diffs are not rendered by default.

97 changes: 92 additions & 5 deletions Source/Blazorise/Components/DateEdit/DateEdit.razor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,41 @@ namespace Blazorise
/// <typeparam name="TValue">Data-type to be binded by the <see cref="Value"/> property.</typeparam>
public partial class DateEdit<TValue> : BaseTextInput<TValue>
{
#region Members

#endregion

#region Methods

/// <inheritdoc/>
public override async Task SetParametersAsync( ParameterView parameters )
{
var dateChanged = parameters.TryGetValue<TValue>( nameof( Date ), out var date ) && !Date.Equals( date );
var minChanged = parameters.TryGetValue( nameof( Min ), out DateTimeOffset? min ) && !Min.IsEqual( min );
var maxChanged = parameters.TryGetValue( nameof( Max ), out DateTimeOffset? max ) && !Max.IsEqual( max );
var firstDayOfWeekChanged = parameters.TryGetValue( nameof( FirstDayOfWeek ), out DayOfWeek firstDayOfWeek ) && !FirstDayOfWeek.IsEqual( firstDayOfWeek );
var displayFormatChanged = parameters.TryGetValue( nameof( DisplayFormat ), out string displayFormat ) && DisplayFormat != displayFormat;

if ( dateChanged )
{
var dateString = FormatValueAsString( date );

await CurrentValueHandler( dateString );

if ( Rendered )
{
ExecuteAfterRender( async () => await JSRunner.UpdateDatePickerValue( ElementRef, ElementId, dateString ) );
}
}

if ( Rendered && ( minChanged || maxChanged || firstDayOfWeekChanged || displayFormatChanged ) )
{
ExecuteAfterRender( async () => await JSRunner.UpdateDatePickerOptions( ElementRef, ElementId, new
{
FirstDayOfWeek = new { Changed = firstDayOfWeekChanged, Value = firstDayOfWeek },
DisplayFormat = new { Changed = displayFormatChanged, Value = displayFormat },
Min = new { Changed = minChanged, Value = min?.ToString( DateFormat ) },
Max = new { Changed = maxChanged, Value = max?.ToString( DateFormat ) },
} ) );
}

// Let blazor do its thing!
await base.SetParametersAsync( parameters );

if ( ParentValidation != null )
Expand All @@ -46,6 +72,47 @@ public override async Task SetParametersAsync( ParameterView parameters )
}
}

protected override async Task OnFirstAfterRenderAsync()
{
await JSRunner.InitializeDatePicker( ElementRef, ElementId, new
{
InputMode = InputMode,
FirstDayOfWeek = FirstDayOfWeek,
DisplayFormat = DisplayFormat,
Default = FormatValueAsString( Date ),
Min = Min?.ToString( DateFormat ),
Max = Max?.ToString( DateFormat ),
} );

await base.OnFirstAfterRenderAsync();
}

/// <inheritdoc/>
protected override async ValueTask DisposeAsync( bool disposing )
{
if ( disposing )
{
if ( Rendered )
{
var task = JSRunner.DestroyDatePicker( ElementRef, ElementId );

try
{
await task;
}
catch
{
if ( !task.IsCanceled )
{
throw;
}
}
}
}

await base.DisposeAsync( disposing );
}

/// <inheritdoc/>
protected override void BuildClasses( ClassBuilder builder )
{
Expand All @@ -69,7 +136,7 @@ protected async Task OnClickHandler( MouseEventArgs e )
if ( Disabled || ReadOnly )
return;

await JSRunner.ActivateDatePicker( ElementId, DateFormat );
await JSRunner.ActivateDatePicker( ElementRef, ElementId, DateFormat );
}

/// <inheritdoc/>
Expand Down Expand Up @@ -173,6 +240,26 @@ protected override Task OnBlurHandler( FocusEventArgs eventArgs )
/// </summary>
[Parameter] public DateTimeOffset? Max { get; set; }

/// <summary>
/// Defines the first day of the week.
/// </summary>
/// <remarks>
/// Be aware that not all providers support setting the first day of the week. This is more
/// the limitations with browsers than it is with the Blazorise. Currently only the material
/// provider support it because it uses the custom plugin for date picker.
/// </remarks>
[Parameter] public DayOfWeek FirstDayOfWeek { get; set; } = DayOfWeek.Sunday;

/// <summary>
/// Defines the display format of the date.
/// </summary>
/// <remarks>
/// Be aware that not all providers support setting the display format. This is more
/// the limitations with browsers than it is with the Blazorise. Currently only the material
/// provider support it because it uses the custom plugin for date picker.
/// </remarks>
[Parameter] public string DisplayFormat { get; set; }

#endregion
}
}
90 changes: 82 additions & 8 deletions Source/Blazorise/Components/TimeEdit/TimeEdit.razor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System;
using System.Linq.Expressions;
using System.Threading.Tasks;
using Blazorise.Extensions;
using Blazorise.Utilities;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Web;
Expand All @@ -15,15 +16,37 @@ namespace Blazorise
/// <typeparam name="TValue">Data-type to be binded by the <see cref="Value"/> property.</typeparam>
public partial class TimeEdit<TValue> : BaseTextInput<TValue>
{
#region Members

#endregion

#region Methods

/// <inheritdoc/>
public override async Task SetParametersAsync( ParameterView parameters )
{
var timeChanged = parameters.TryGetValue( nameof( Time ), out TValue time ) && !Time.IsEqual( time );
var minChanged = parameters.TryGetValue( nameof( Min ), out TimeSpan? min ) && !Min.IsEqual( min );
var maxChanged = parameters.TryGetValue( nameof( Max ), out TimeSpan? max ) && !Max.IsEqual( max );

if ( timeChanged )
{
var timeString = FormatValueAsString( time );

await CurrentValueHandler( timeString );

if ( Rendered )
{
ExecuteAfterRender( async () => await JSRunner.UpdateTimePickerValue( ElementRef, ElementId, timeString ) );
}
}

if ( Rendered && ( minChanged || maxChanged ) )
{
ExecuteAfterRender( async () => await JSRunner.UpdateTimePickerOptions( ElementRef, ElementId, new
{
Min = new { Changed = minChanged, Value = min?.ToString( Parsers.InternalTimeFormat ) },
Max = new { Changed = maxChanged, Value = max?.ToString( Parsers.InternalTimeFormat ) },
} ) );
}

// Let blazor do its thing!
await base.SetParametersAsync( parameters );

if ( ParentValidation != null )
Expand All @@ -45,6 +68,44 @@ public override async Task SetParametersAsync( ParameterView parameters )
}
}

protected override async Task OnFirstAfterRenderAsync()
{
await JSRunner.InitializeTimePicker( ElementRef, ElementId, new
{
Default = FormatValueAsString( Time ),
Min = Min?.ToString( Parsers.InternalTimeFormat ),
Max = Max?.ToString( Parsers.InternalTimeFormat ),
} );

await base.OnFirstAfterRenderAsync();
}

/// <inheritdoc/>
protected override async ValueTask DisposeAsync( bool disposing )
{
if ( disposing )
{
if ( Rendered )
{
var task = JSRunner.DestroyTimePicker( ElementRef, ElementId );

try
{
await task;
}
catch
{
if ( !task.IsCanceled )
{
throw;
}
}
}
}

await base.DisposeAsync( disposing );
}

/// <inheritdoc/>
protected override void BuildClasses( ClassBuilder builder )
{
Expand All @@ -64,7 +125,10 @@ protected override Task OnChangeHandler( ChangeEventArgs e )

protected async Task OnClickHandler( MouseEventArgs e )
{
await JSRunner.ActivateTimePicker( ElementId, Parsers.InternalTimeFormat );
if ( Disabled || ReadOnly )
return;

await JSRunner.ActivateTimePicker( ElementRef, ElementId, Parsers.InternalTimeFormat );
}

/// <inheritdoc/>
Expand Down Expand Up @@ -126,20 +190,30 @@ protected override Task OnBlurHandler( FocusEventArgs eventArgs )
protected override TValue InternalValue { get => Time; set => Time = value; }

/// <summary>
/// Gets or sets the input date value.
/// Gets or sets the input time value.
/// </summary>
[Parameter] public TValue Time { get; set; }

/// <summary>
/// Occurs when the date has changed.
/// Occurs when the time has changed.
/// </summary>
[Parameter] public EventCallback<TValue> TimeChanged { get; set; }

/// <summary>
/// Gets or sets an expression that identifies the date value.
/// Gets or sets an expression that identifies the time field.
/// </summary>
[Parameter] public Expression<Func<TValue>> TimeExpression { get; set; }

/// <summary>
/// The earliest time to accept.
/// </summary>
[Parameter] public TimeSpan? Min { get; set; }

/// <summary>
/// The latest time to accept.
/// </summary>
[Parameter] public TimeSpan? Max { get; set; }

#endregion
}
}
Loading

0 comments on commit c174b5e

Please sign in to comment.