diff --git a/BlazorBootstrap.Demo.RCL/Components/Pages/Charts/LineCharts/LineChartDocumentation.razor.orig b/BlazorBootstrap.Demo.RCL/Components/Pages/Charts/LineCharts/LineChartDocumentation.razor.orig new file mode 100644 index 000000000..593cfd416 --- /dev/null +++ b/BlazorBootstrap.Demo.RCL/Components/Pages/Charts/LineCharts/LineChartDocumentation.razor.orig @@ -0,0 +1,64 @@ +@page "/charts/line-chart" + +@title + + + +

Blazor Line Chart

+
+ A Blazor Bootstrap line chart component is a graphical representation of data that uses a series of connected points to show how the data changes over time. + It is a type of x-y chart, where the x-axis represents the independent variable, such as time, and the y-axis represents the dependent variable, such as the value. +
+ + + + +
+ Refer to the getting started guide for setting up charts. +
+ + +
+ In the following example, a categorical 12-color palette is used. +
+ + For data visualization, you can use the predefined palettes ColorUtility.CategoricalTwelveColors for a 12-color palette and ColorUtility.CategoricalSixColors for a 6-color palette. + These palettes offer a range of distinct and visually appealing colors that can be applied to represent different categories or data elements in your visualizations. + + +
+ + + +
+ By default, the chart is using the default locale of the platform on which it is running. + In the following example, you will see the chart in the German locale (de_DE). +
+ + + + + + + + + + + + + + +<<<<<<< HEAD + + +======= + + +>>>>>>> pr-chartjs-plugins + +@code { + private readonly string pageUrl = "/charts/line-chart"; + private readonly string title = "Blazor Line Chart"; + private readonly string description = "A Blazor Bootstrap line chart component is a graphical representation of data that uses a series of connected points to show how the data changes over time. It is a type of x-y chart, where the x-axis represents the independent variable, such as time, and the y-axis represents the dependent variable, such as the value."; + private readonly string imageUrl = "https://i.imgur.com/8b7jH0D.png"; +} \ No newline at end of file diff --git a/BlazorBootstrap.Demo.RCL/Components/Pages/Offcanvas/OffcanvasDocumentation.razor b/BlazorBootstrap.Demo.RCL/Components/Pages/Offcanvas/OffcanvasDocumentation.razor index 5fd4b28ef..c9d645ae6 100644 --- a/BlazorBootstrap.Demo.RCL/Components/Pages/Offcanvas/OffcanvasDocumentation.razor +++ b/BlazorBootstrap.Demo.RCL/Components/Pages/Offcanvas/OffcanvasDocumentation.razor @@ -6,7 +6,7 @@

Blazor Offcanvas

- Build hidden sidebars into your project for navigation, shopping carts, and more with a offcanvas component. + Build hidden sidebars into your project for navigation, shopping carts, and more with a offcanvas component.
@@ -19,7 +19,7 @@
Render different components dynamically within the offcanvas without iterating through possible types or using conditional logic.
- If dynamically-rendered components have component parameters, pass them as an IDictionary. The string is the parameter's name, and the object is the parameter's value. + If dynamically-rendered components have component parameters, pass them as an IDictionary. The string is the parameter's name, and the object is the parameter's value.
EmployeeDemoComponent1.razor @@ -28,12 +28,12 @@
Event callbacks (EventCallback) can be passed in its parameter dictionary.
- In the following parent component example, the ShowDTMessage method assigns a string with the current time to message, and the value of message is rendered. - The parent component passes the callback method, ShowDTMessage in the parameter dictionary: -
    -
  • The string key is the callback method's name, OnClickCallback.
  • -
  • The object value is created by EventCallbackFactory.Create for the parent callback method, ShowDTMessage.
  • -
+ In the following parent component example, the ShowDTMessage method assigns a string with the current time to message, and the value of message is rendered. + The parent component passes the callback method, ShowDTMessage in the parameter dictionary: +
    +
  • The string key is the callback method's name, OnClickCallback.
  • +
  • The object value is created by EventCallbackFactory.Create for the parent callback method, ShowDTMessage.
  • +
EmployeeDemoComponent2.razor @@ -45,9 +45,9 @@ Default placement for the offcanvas component is right. - -
When UseStaticBackdrop is set to true, the offcanvas will not close when clicking outside of it.
- + +
When Backdrop is set to Offcanvas.BackdropType.Static, the offcanvas will not close when clicking outside of it.
+
Set the size of the Offcanvas with the Size parameter. The default value is OffcanvasSize.Regular.
@@ -58,9 +58,21 @@
Blazor Bootstrap offcanvas component exposes a few events for hooking into offcanvas functionality.
+ +
When IsScrollable to true the page will be scrollable and interactable below the offcanvas backdrop.
+
+ Note: This demo does not work because the main viewport has overflow: hidden set in the CSS. +
+ + + +
You can read IsVisible to get the current status and use @@bind-IsVisible to toggle the offcanvas with a switch.
+ + + @code { - private string pageUrl = "/offcanvas"; - private string title = "Blazor Offcanvas Component"; - private string description = "Build hidden sidebars into your project for navigation, shopping carts, and more with Blazor Bootstrap offcanvas component."; - private string imageUrl = "https://i.imgur.com/1vNz5Ci.jpg"; + private string pageUrl = "/offcanvas"; + private string title = "Blazor Offcanvas Component"; + private string description = "Build hidden sidebars into your project for navigation, shopping carts, and more with Blazor Bootstrap offcanvas component."; + private string imageUrl = "https://i.imgur.com/1vNz5Ci.jpg"; } diff --git a/BlazorBootstrap.Demo.RCL/Components/Pages/Offcanvas/Offcanvas_Demo_04_Backdrops.razor b/BlazorBootstrap.Demo.RCL/Components/Pages/Offcanvas/Offcanvas_Demo_04_Backdrops.razor new file mode 100644 index 000000000..740757c48 --- /dev/null +++ b/BlazorBootstrap.Demo.RCL/Components/Pages/Offcanvas/Offcanvas_Demo_04_Backdrops.razor @@ -0,0 +1,28 @@ +@foreach( var backdrop in backdropTypes ) +{ + offcanvas.TryAdd( backdrop, default! ); + + +

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec tincidunt blandit mauris. Aliquam sit amet lorem laoreet, laoreet elit ut, placerat tellus. In mollis ultricies elit, volutpat maximus ipsum sodales interdum. Suspendisse eget tellus mollis, rutrum mauris ac, vulputate enim. Cras porta neque vitae lacinia elementum. Nunc sit amet pulvinar nibh. Curabitur interdum eget odio in tempor. Nulla dictum orci quis ligula auctor fermentum. Pellentesque finibus tellus ac massa convallis malesuada. Nam id pharetra velit, sed eleifend mi. Sed sed justo lorem. Quisque et nulla ut dolor feugiat vestibulum. Nunc at porttitor orci, at dignissim metus. Donec vitae metus vitae felis semper placerat.

+

Proin quis congue enim, ut ultricies erat. Nulla facilisi. Fusce pretium, metus eget tempor vehicula, nisl lorem tincidunt metus, consectetur molestie lorem leo vel lectus. Vivamus pellentesque pharetra mattis. Aenean dignissim quam non velit ultrices rutrum. Aliquam lacinia faucibus sapien vel pretium. Nullam libero massa, ultricies id lacinia nec, scelerisque ut felis. Vivamus ac egestas urna, sit amet condimentum odio. Suspendisse ultrices, libero sed interdum pulvinar, lectus felis pellentesque enim, eu finibus magna massa id augue. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis eget tempor libero. Cras ut interdum purus. Donec eu pulvinar urna, ut porttitor purus. Suspendisse sed sodales nunc. Quisque posuere augue sed luctus placerat.

+

Morbi ullamcorper risus turpis, et ullamcorper nulla semper vitae. Proin pharetra dolor dui, non condimentum ex fermentum in. Vestibulum pharetra, risus et pulvinar eleifend, nulla tortor blandit risus, ac imperdiet elit massa quis leo. Vivamus urna lacus, luctus eget felis id, eleifend tristique nisl. Sed dignissim mollis ligula vitae laoreet. Vestibulum eget magna nisi. Aenean auctor elit et turpis blandit, eget porttitor felis suscipit. Duis placerat, sapien a sodales tempus, odio orci malesuada neque, ac molestie ipsum nisi vel eros. Integer sem lectus, luctus vitae sapien ut, efficitur aliquam sem. Praesent placerat est eros, vulputate rutrum nunc imperdiet vitae. Fusce sed felis eget purus aliquet convallis eu eget lacus. Sed finibus nec magna et accumsan. Donec vitae tellus eros. Nullam et ex vitae est sagittis malesuada. Vivamus molestie malesuada libero, a consequat magna dapibus pellentesque. Cras molestie tortor vitae congue pretium.

+

Pellentesque nec iaculis justo, sed pretium sem. Mauris finibus lacus at mollis fringilla. Etiam auctor in justo ac bibendum. Vestibulum at lorem accumsan, maximus erat suscipit, suscipit ex. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris dignissim id quam sit amet varius. Etiam pretium ultrices dignissim. Cras at tortor hendrerit metus ultrices lobortis at ac est. Suspendisse consectetur pellentesque nunc sit amet scelerisque. Maecenas feugiat nunc laoreet, auctor erat eget, ultricies ex. Aliquam nisi nulla, cursus et ante ut, interdum volutpat leo. Phasellus laoreet aliquam maximus. Vestibulum eu neque porta, consectetur ipsum non, euismod enim. Vestibulum euismod purus elit, ultrices imperdiet nisl porttitor eget. Vivamus eros turpis, tincidunt a vulputate vel, malesuada tristique nulla.

+

Vestibulum sed aliquam urna. Ut ullamcorper erat vitae velit mattis commodo. Phasellus dignissim rhoncus dapibus. Quisque congue egestas tellus id finibus. Suspendisse nibh felis, mattis et finibus vel, tempor in lectus. Nullam eget eros dui. Mauris eget vestibulum nibh. Nullam mattis malesuada lorem vel condimentum. Mauris id odio ac est feugiat condimentum.

+
+ + + +
+} + +@foreach( var backdrop in backdropTypes ) +{ + +} + +@code { + private IEnumerable backdropTypes = Enum.GetValues( typeof( Offcanvas.BackdropType ) ).Cast(); + private Dictionary offcanvas = new(); + + private async Task OnShowOffcanvasClick( Offcanvas.BackdropType backdrop ) => await offcanvas[ backdrop ].ShowAsync(); +} \ No newline at end of file diff --git a/BlazorBootstrap.Demo.RCL/Components/Pages/Offcanvas/Offcanvas_Demo_04_Static_Backdrop.razor b/BlazorBootstrap.Demo.RCL/Components/Pages/Offcanvas/Offcanvas_Demo_04_Static_Backdrop.razor deleted file mode 100644 index f3479871c..000000000 --- a/BlazorBootstrap.Demo.RCL/Components/Pages/Offcanvas/Offcanvas_Demo_04_Static_Backdrop.razor +++ /dev/null @@ -1,19 +0,0 @@ - - -

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec tincidunt blandit mauris. Aliquam sit amet lorem laoreet, laoreet elit ut, placerat tellus. In mollis ultricies elit, volutpat maximus ipsum sodales interdum. Suspendisse eget tellus mollis, rutrum mauris ac, vulputate enim. Cras porta neque vitae lacinia elementum. Nunc sit amet pulvinar nibh. Curabitur interdum eget odio in tempor. Nulla dictum orci quis ligula auctor fermentum. Pellentesque finibus tellus ac massa convallis malesuada. Nam id pharetra velit, sed eleifend mi. Sed sed justo lorem. Quisque et nulla ut dolor feugiat vestibulum. Nunc at porttitor orci, at dignissim metus. Donec vitae metus vitae felis semper placerat.

-

Proin quis congue enim, ut ultricies erat. Nulla facilisi. Fusce pretium, metus eget tempor vehicula, nisl lorem tincidunt metus, consectetur molestie lorem leo vel lectus. Vivamus pellentesque pharetra mattis. Aenean dignissim quam non velit ultrices rutrum. Aliquam lacinia faucibus sapien vel pretium. Nullam libero massa, ultricies id lacinia nec, scelerisque ut felis. Vivamus ac egestas urna, sit amet condimentum odio. Suspendisse ultrices, libero sed interdum pulvinar, lectus felis pellentesque enim, eu finibus magna massa id augue. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis eget tempor libero. Cras ut interdum purus. Donec eu pulvinar urna, ut porttitor purus. Suspendisse sed sodales nunc. Quisque posuere augue sed luctus placerat.

-

Morbi ullamcorper risus turpis, et ullamcorper nulla semper vitae. Proin pharetra dolor dui, non condimentum ex fermentum in. Vestibulum pharetra, risus et pulvinar eleifend, nulla tortor blandit risus, ac imperdiet elit massa quis leo. Vivamus urna lacus, luctus eget felis id, eleifend tristique nisl. Sed dignissim mollis ligula vitae laoreet. Vestibulum eget magna nisi. Aenean auctor elit et turpis blandit, eget porttitor felis suscipit. Duis placerat, sapien a sodales tempus, odio orci malesuada neque, ac molestie ipsum nisi vel eros. Integer sem lectus, luctus vitae sapien ut, efficitur aliquam sem. Praesent placerat est eros, vulputate rutrum nunc imperdiet vitae. Fusce sed felis eget purus aliquet convallis eu eget lacus. Sed finibus nec magna et accumsan. Donec vitae tellus eros. Nullam et ex vitae est sagittis malesuada. Vivamus molestie malesuada libero, a consequat magna dapibus pellentesque. Cras molestie tortor vitae congue pretium.

-

Pellentesque nec iaculis justo, sed pretium sem. Mauris finibus lacus at mollis fringilla. Etiam auctor in justo ac bibendum. Vestibulum at lorem accumsan, maximus erat suscipit, suscipit ex. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris dignissim id quam sit amet varius. Etiam pretium ultrices dignissim. Cras at tortor hendrerit metus ultrices lobortis at ac est. Suspendisse consectetur pellentesque nunc sit amet scelerisque. Maecenas feugiat nunc laoreet, auctor erat eget, ultricies ex. Aliquam nisi nulla, cursus et ante ut, interdum volutpat leo. Phasellus laoreet aliquam maximus. Vestibulum eu neque porta, consectetur ipsum non, euismod enim. Vestibulum euismod purus elit, ultrices imperdiet nisl porttitor eget. Vivamus eros turpis, tincidunt a vulputate vel, malesuada tristique nulla.

-

Vestibulum sed aliquam urna. Ut ullamcorper erat vitae velit mattis commodo. Phasellus dignissim rhoncus dapibus. Quisque congue egestas tellus id finibus. Suspendisse nibh felis, mattis et finibus vel, tempor in lectus. Nullam eget eros dui. Mauris eget vestibulum nibh. Nullam mattis malesuada lorem vel condimentum. Mauris id odio ac est feugiat condimentum.

-
- - - -
- - - -@code { - private Offcanvas offcanvas = default!; - private async Task OnShowOffcanvasClick() => await offcanvas.ShowAsync(); -} \ No newline at end of file diff --git a/BlazorBootstrap.Demo.RCL/Components/Pages/Offcanvas/Offcanvas_Demo_07_Scrollable.razor b/BlazorBootstrap.Demo.RCL/Components/Pages/Offcanvas/Offcanvas_Demo_07_Scrollable.razor new file mode 100644 index 000000000..9f771f696 --- /dev/null +++ b/BlazorBootstrap.Demo.RCL/Components/Pages/Offcanvas/Offcanvas_Demo_07_Scrollable.razor @@ -0,0 +1,12 @@ + + ... + + + +

After showing the canvas, note how you can still scroll this page and interact with it.

+ +@code { + private Offcanvas offcanvas = default!; + + private async Task OnShowOffcanvasClick() => await offcanvas.ShowAsync(); +} \ No newline at end of file diff --git a/BlazorBootstrap.Demo.RCL/Components/Pages/Offcanvas/Offcanvas_Demo_08_Bind_IsVisible.razor b/BlazorBootstrap.Demo.RCL/Components/Pages/Offcanvas/Offcanvas_Demo_08_Bind_IsVisible.razor new file mode 100644 index 000000000..a692b6247 --- /dev/null +++ b/BlazorBootstrap.Demo.RCL/Components/Pages/Offcanvas/Offcanvas_Demo_08_Bind_IsVisible.razor @@ -0,0 +1,20 @@ + + + + + Note that no @@ref is needed to bind the property. + + + +
+ The offcanvas is @(IsVisible ? "visible" : "hidden"). + + +
+
+ +
+ +@code { + public bool IsVisible { get; set; } +} \ No newline at end of file diff --git a/blazorbootstrap/Components/Offcanvas/Offcanvas.razor b/blazorbootstrap/Components/Offcanvas/Offcanvas.razor index c88ac52e7..d981943fa 100644 --- a/blazorbootstrap/Components/Offcanvas/Offcanvas.razor +++ b/blazorbootstrap/Components/Offcanvas/Offcanvas.razor @@ -2,40 +2,40 @@ @inherits BlazorBootstrapComponentBase
- @if (!string.IsNullOrWhiteSpace(Title) || HeaderTemplate != null || ShowCloseButton) - { -
- @if (!string.IsNullOrWhiteSpace(title)) - { -
@title
- } - else if (HeaderTemplate is not null) - { - @HeaderTemplate - } + @if( !string.IsNullOrWhiteSpace( Title ) || HeaderTemplate != null || ShowCloseButton ) + { +
+ @if( !string.IsNullOrWhiteSpace( title ) ) + { +
@title
+ } + else if( HeaderTemplate is not null ) + { + @HeaderTemplate + } - @if (ShowCloseButton) - { - - } -
- } - @if (childComponent is not null) - { -
- -
- } - else if (BodyTemplate != null) - { -
- @BodyTemplate -
- } - @if (FooterTemplate != null) - { - - } + @if( ShowCloseButton ) + { + + } +
+ } + @if( childComponent is not null ) + { +
+ +
+ } + else if( BodyTemplate != null ) + { +
+ @BodyTemplate +
+ } + @if( FooterTemplate != null ) + { + + }
diff --git a/blazorbootstrap/Components/Offcanvas/Offcanvas.razor.cs b/blazorbootstrap/Components/Offcanvas/Offcanvas.razor.cs index 7c3d705c6..24edd07dc 100644 --- a/blazorbootstrap/Components/Offcanvas/Offcanvas.razor.cs +++ b/blazorbootstrap/Components/Offcanvas/Offcanvas.razor.cs @@ -1,271 +1,321 @@ -namespace BlazorBootstrap; +using System.Reflection.Metadata; + +namespace BlazorBootstrap; public partial class Offcanvas : BlazorBootstrapComponentBase { - #region Fields and Constants - - private Type? childComponent; - - private DotNetObjectReference objRef = default!; - - private Dictionary parameters = default!; + #region Fields and Constants - private string title = default!; + private Type? childComponent; - #endregion + private DotNetObjectReference objRef = default!; - #region Methods + private Dictionary parameters = default!; - /// - protected override async ValueTask DisposeAsyncCore(bool disposing) - { - if (disposing) - { - try - { - if (IsRenderComplete) - await JSRuntime.InvokeVoidAsync("window.blazorBootstrap.offcanvas.dispose", Id); - } - catch (JSDisconnectedException) - { - // do nothing - } - - objRef?.Dispose(); - } - - await base.DisposeAsyncCore(disposing); - } + private string title = default!; - protected override async Task OnAfterRenderAsync(bool firstRender) - { - if (firstRender) - await JSRuntime.InvokeVoidAsync("window.blazorBootstrap.offcanvas.initialize", Id, UseStaticBackdrop, CloseOnEscape, IsScrollable, objRef); + #endregion - await base.OnAfterRenderAsync(firstRender); - } + #region Methods - protected override async Task OnInitializedAsync() + /// + protected override async ValueTask DisposeAsyncCore( bool disposing ) + { + if( disposing ) { - objRef ??= DotNetObjectReference.Create(this); - - title = Title; - - await base.OnInitializedAsync(); + try + { + if( IsRenderComplete ) + await JSRuntime.InvokeVoidAsync( "window.blazorBootstrap.offcanvas.dispose", Id ); + } + catch( JSDisconnectedException ) + { + // do nothing + } + + objRef?.Dispose(); } - [JSInvokable] - public async Task bsHiddenOffcanvas() => await OnHidden.InvokeAsync(); - - [JSInvokable] - public async Task bsHideOffcanvas() => await OnHiding.InvokeAsync(); - - [JSInvokable] - public async Task bsShownOffcanvas() => await OnShown.InvokeAsync(); - - [JSInvokable] - public async Task bsShowOffcanvas() => await OnShowing.InvokeAsync(); - - /// - /// Hides an offcanvas. - /// - public async Task HideAsync() => await JSRuntime.InvokeVoidAsync("window.blazorBootstrap.offcanvas.hide", Id); - - /// - /// Shows an offcanvas. - /// - public async Task ShowAsync() => await ShowAsync(null, null, null); - - /// - /// Opens a offcanvas. - /// - /// - /// - /// - public async Task ShowAsync(string title, Dictionary? parameters = null) => await ShowAsync(title, typeof(T), parameters); + await base.DisposeAsyncCore( disposing ); + } - private async Task ShowAsync(string? title, Type? type, Dictionary? parameters) + protected override async Task OnAfterRenderAsync( bool firstRender ) + { + if( firstRender ) { - if (!string.IsNullOrWhiteSpace(title)) - this.title = title; - - childComponent = type; - this.parameters = parameters!; - await JSRuntime.InvokeVoidAsync("window.blazorBootstrap.offcanvas.show", Id); - await InvokeAsync(StateHasChanged); + object backdrop = Backdrop switch + { + BackdropType.None => false, + BackdropType.Visible => true, + BackdropType.Static => "static", + _ => throw new InvalidOperationException( "Invalid backdrop value" ) + }; + + await JSRuntime.InvokeVoidAsync( "window.blazorBootstrap.offcanvas.initialize", Id, backdrop, CloseOnEscape, IsScrollable, objRef ); } - #endregion - - #region Properties, Indexers - - protected override string? ClassNames => - BuildClassNames(Class, - (BootstrapClass.Offcanvas, true), - (Placement.ToOffcanvasPlacementClass(), true), - (Size.ToOffcanvasSizeClass(), true)); - - /// - /// Gets or sets the body CSS class. - /// - /// - /// Default value is null. - /// - [Parameter] - public string BodyCssClass { get; set; } = default!; - - /// - /// Gets or sets the body template. - /// - /// - /// Default value is null. - /// - [Parameter] - public RenderFragment BodyTemplate { get; set; } = default!; - - /// - /// If , offcanvas closes when escape key is pressed. - /// - /// - /// Default value is true. - /// - [Parameter] - public bool CloseOnEscape { get; set; } = true; - - /// - /// Gets or sets the footer CSS class. - /// - /// - /// Default value is null. - /// - [Parameter] - public string FooterCssClass { get; set; } = default!; - - /// - /// Gets or sets the footer template. - /// - /// - /// Default value is null. - /// - [Parameter] - public RenderFragment FooterTemplate { get; set; } = default!; + await base.OnAfterRenderAsync( firstRender ); + } - /// - /// Gets or sets the header CSS class. - /// - /// - /// Default value is null. - /// - [Parameter] - public string HeaderCssClass { get; set; } = default!; + protected override async Task OnInitializedAsync() + { + objRef ??= DotNetObjectReference.Create( this ); - /// - /// Gets or sets the header template. - /// - /// - /// Default value is null. - /// - [Parameter] - public RenderFragment HeaderTemplate { get; set; } = default!; + title = Title; - /// - /// Indicates whether body scrolling is allowed while offcanvas is open. - /// - /// - /// Default value is false. - /// - [Parameter] - public bool IsScrollable { get; set; } + await base.OnInitializedAsync(); + } - /// - /// This event is fired when an offcanvas element has been hidden from the user (will wait for CSS transitions to - /// complete). - /// - [Parameter] - public EventCallback OnHidden { get; set; } + [JSInvokable] + public async Task bsHiddenOffcanvas() => await OnHidden.InvokeAsync(); - /// - /// This event is fired immediately when the hide method has been called. - /// - [Parameter] - public EventCallback OnHiding { get; set; } + [JSInvokable] + public async Task bsHideOffcanvas() + { + this.isVisible = false; + await this.IsVisibleChanged.InvokeAsync( this.isVisible ); - /// - /// This event fires immediately when the show instance method is called. - /// - [Parameter] - public EventCallback OnShowing { get; set; } + await OnHiding.InvokeAsync(); + } - /// - /// This event is fired when an offcanvas element has been made visible to the user (will wait for CSS transitions to - /// complete). - /// - [Parameter] - public EventCallback OnShown { get; set; } + [JSInvokable] + public async Task bsShownOffcanvas() => await OnShown.InvokeAsync(); - /// - /// Gets or sets the offcanvas placement. - /// - /// - /// Default value is . - /// - [Parameter] - public Placement Placement { get; set; } = Placement.End; + [JSInvokable] + public async Task bsShowOffcanvas() + { + this.isVisible = true; + await this.IsVisibleChanged.InvokeAsync( this.isVisible ); - /// - /// If , modal shows close button in the header. - /// - /// - /// Default value is true. - /// - [Parameter] - public bool ShowCloseButton { get; set; } = true; + await OnShowing.InvokeAsync(); + } - /// - /// Gets or sets the offcanvas size. - /// - /// - /// Default value is . - /// - [Parameter] - public OffcanvasSize Size { get; set; } = OffcanvasSize.Regular; + /// + /// Hides an offcanvas. + /// + public async Task HideAsync() => await JSRuntime.InvokeVoidAsync( "window.blazorBootstrap.offcanvas.hide", Id ); - /// - /// Gets or sets the tab index. - /// - /// - /// Default value is -1. - /// - [Parameter] - public int TabIndex { get; set; } = -1; + /// + /// Shows an offcanvas. + /// + public async Task ShowAsync() => await ShowAsync( null, null, null ); + /// + /// Shows or hides the offcanvas, depending on the value of the parameter + /// + /// The requested new state of the offcanvas. + public async Task ToggleAsync( bool isVisible ) + { + if( this.isVisible != isVisible ) + { + await ( isVisible ? ShowAsync() : HideAsync() ); + } + } + + /// + /// Opens a offcanvas. + /// + /// + /// + /// + public async Task ShowAsync( string title, Dictionary? parameters = null ) => await ShowAsync( title, typeof( T ), parameters ); + + private async Task ShowAsync( string? title, Type? type, Dictionary? parameters ) + { + if( !string.IsNullOrWhiteSpace( title ) ) + this.title = title; + + childComponent = type; + this.parameters = parameters!; + await JSRuntime.InvokeVoidAsync( "window.blazorBootstrap.offcanvas.show", Id ); + await InvokeAsync( StateHasChanged ); + } + + #endregion + + #region Properties, Indexers + + private bool isVisible; + + [Parameter] + public bool IsVisible + { + get => this.isVisible; + set => ToggleAsync( value ); + } + + [Parameter] + public EventCallback IsVisibleChanged { get; set; } + + protected override string? ClassNames => + BuildClassNames( Class, + (BootstrapClass.Offcanvas, true), + (Placement.ToOffcanvasPlacementClass(), true), + (Size.ToOffcanvasSizeClass(), true) ); + + /// + /// Gets or sets the body CSS class. + /// + /// + /// Default value is null. + /// + [Parameter] + public string BodyCssClass { get; set; } = default!; + + /// + /// Gets or sets the body template. + /// + /// + /// Default value is null. + /// + [Parameter] + public RenderFragment BodyTemplate { get; set; } = default!; + + /// + /// If , offcanvas closes when escape key is pressed. + /// + /// + /// Default value is true. + /// + [Parameter] + public bool CloseOnEscape { get; set; } = true; + + /// + /// Gets or sets the footer CSS class. + /// + /// + /// Default value is null. + /// + [Parameter] + public string FooterCssClass { get; set; } = default!; + + /// + /// Gets or sets the footer template. + /// + /// + /// Default value is null. + /// + [Parameter] + public RenderFragment FooterTemplate { get; set; } = default!; + + /// + /// Gets or sets the header CSS class. + /// + /// + /// Default value is null. + /// + [Parameter] + public string HeaderCssClass { get; set; } = default!; + + /// + /// Gets or sets the header template. + /// + /// + /// Default value is null. + /// + [Parameter] + public RenderFragment HeaderTemplate { get; set; } = default!; + + /// + /// Indicates whether body scrolling is allowed while offcanvas is open. + /// + /// + /// Default value is false. + /// + [Parameter] + public bool IsScrollable { get; set; } + + /// + /// This event is fired when an offcanvas element has been hidden from the user (will wait for CSS transitions to + /// complete). + /// + [Parameter] + public EventCallback OnHidden { get; set; } + + /// + /// This event is fired immediately when the hide method has been called. + /// + [Parameter] + public EventCallback OnHiding { get; set; } + + /// + /// This event fires immediately when the show instance method is called. + /// + [Parameter] + public EventCallback OnShowing { get; set; } + + /// + /// This event is fired when an offcanvas element has been made visible to the user (will wait for CSS transitions to + /// complete). + /// + [Parameter] + public EventCallback OnShown { get; set; } + + /// + /// Gets or sets the offcanvas placement. + /// + /// + /// Default value is . + /// + [Parameter] + public Placement Placement { get; set; } = Placement.End; + + /// + /// If , modal shows close button in the header. + /// + /// + /// Default value is true. + /// + [Parameter] + public bool ShowCloseButton { get; set; } = true; + + /// + /// Gets or sets the offcanvas size. + /// + /// + /// Default value is . + /// + [Parameter] + public OffcanvasSize Size { get; set; } = OffcanvasSize.Regular; + + /// + /// Gets or sets the tab index. + /// + /// + /// Default value is -1. + /// + [Parameter] + public int TabIndex { get; set; } = -1; + + /// + /// Gets or sets the offcanvas title. + /// + /// + /// Default value is null. + /// + [Parameter] + public string Title { get; set; } = default!; + + [Parameter] + public BackdropType Backdrop { get; set; } = BackdropType.Visible; + + public enum BackdropType + { /// - /// Gets or sets the offcanvas title. + /// Do not use a backdrop, the page will stay visible. /// - /// - /// Default value is null. - /// - [Parameter] - public string Title { get; set; } = default!; + None, - [Obsolete("Use `UseStaticBackdrop` parameter.")] /// - /// Indicates whether to apply a backdrop on body while offcanvas is open. + /// Visible backdrop, the page will be covered by a backdrop /// - /// - /// Default value is true. - /// - [Parameter] - public bool UseBackdrop { get; set; } = true; + Visible, /// - /// When `UseStaticBackdrop` is set to true, the offcanvas will not close when clicking outside of it. + /// Static backdrop, the page will be covered by a backdrop and the offcanvas will not close when clicking outside of it. /// - /// - /// Default value is false. - /// - [Parameter] - public bool UseStaticBackdrop { get; set; } + Static + } - #endregion + #endregion } diff --git a/blazorbootstrap/wwwroot/blazor.bootstrap.js b/blazorbootstrap/wwwroot/blazor.bootstrap.js index 1d45c7a38..cc1b838a8 100644 --- a/blazorbootstrap/wwwroot/blazor.bootstrap.js +++ b/blazorbootstrap/wwwroot/blazor.bootstrap.js @@ -249,57 +249,57 @@ window.blazorBootstrap = { bodyEl[0].style['overflow'] = 'auto'; } }, - carousel: { - cycle: (elementId) => { - let carouselEl = document.getElementById(elementId); - if (carouselEl != null) - bootstrap?.Carousel?.getOrCreateInstance(carouselEl)?.cycle(); - }, - dispose: (elementId) => { - let carouselEl = document.getElementById(elementId); - if (carouselEl != null) - bootstrap?.Carousel?.getOrCreateInstance(carouselEl)?.dispose(); - }, - initialize: (elementId, options, dotNetHelper) => { - let carouselEl = document.getElementById(elementId); - if (carouselEl == null) - return; - - carouselEl.addEventListener('slid.bs.carousel', function (e) { - dotNetHelper.invokeMethodAsync('bsSlid', e); - }); - carouselEl.addEventListener('slide.bs.carousel', function (e) { - dotNetHelper.invokeMethodAsync('bslide', e); - }); - - bootstrap?.Carousel?.getOrCreateInstance(carouselEl, options); - }, - next: (elementId) => { - let carouselEl = document.getElementById(elementId); - if (carouselEl != null) - bootstrap?.Carousel?.getOrCreateInstance(carouselEl)?.next(); - }, - nextWhenVisible: (elementId) => { - let carouselEl = document.getElementById(elementId); - if (carouselEl != null) - bootstrap?.Carousel?.getOrCreateInstance(carouselEl)?.nextWhenVisible(); - }, - pause: (elementId) => { - let carouselEl = document.getElementById(elementId); - if (carouselEl != null) - bootstrap?.Carousel?.getOrCreateInstance(carouselEl)?.pause(); - }, - prev: (elementId) => { - let carouselEl = document.getElementById(elementId); - if (carouselEl != null) - bootstrap?.Carousel?.getOrCreateInstance(carouselEl)?.prev(); - }, - to: (elementId, index) => { - let carouselEl = document.getElementById(elementId); - if (carouselEl != null) - bootstrap?.Carousel?.getOrCreateInstance(carouselEl)?.to(index); - }, - }, + carousel: { + cycle: (elementId) => { + let carouselEl = document.getElementById(elementId); + if (carouselEl != null) + bootstrap?.Carousel?.getOrCreateInstance(carouselEl)?.cycle(); + }, + dispose: (elementId) => { + let carouselEl = document.getElementById(elementId); + if (carouselEl != null) + bootstrap?.Carousel?.getOrCreateInstance(carouselEl)?.dispose(); + }, + initialize: (elementId, options, dotNetHelper) => { + let carouselEl = document.getElementById(elementId); + if (carouselEl == null) + return; + + carouselEl.addEventListener('slid.bs.carousel', function (e) { + dotNetHelper.invokeMethodAsync('bsSlid', e); + }); + carouselEl.addEventListener('slide.bs.carousel', function (e) { + dotNetHelper.invokeMethodAsync('bslide', e); + }); + + bootstrap?.Carousel?.getOrCreateInstance(carouselEl, options); + }, + next: (elementId) => { + let carouselEl = document.getElementById(elementId); + if (carouselEl != null) + bootstrap?.Carousel?.getOrCreateInstance(carouselEl)?.next(); + }, + nextWhenVisible: (elementId) => { + let carouselEl = document.getElementById(elementId); + if (carouselEl != null) + bootstrap?.Carousel?.getOrCreateInstance(carouselEl)?.nextWhenVisible(); + }, + pause: (elementId) => { + let carouselEl = document.getElementById(elementId); + if (carouselEl != null) + bootstrap?.Carousel?.getOrCreateInstance(carouselEl)?.pause(); + }, + prev: (elementId) => { + let carouselEl = document.getElementById(elementId); + if (carouselEl != null) + bootstrap?.Carousel?.getOrCreateInstance(carouselEl)?.prev(); + }, + to: (elementId, index) => { + let carouselEl = document.getElementById(elementId); + if (carouselEl != null) + bootstrap?.Carousel?.getOrCreateInstance(carouselEl)?.to(index); + }, + }, currencyInput: { initialize: (elementId, isFloat, allowNegativeNumbers, decimalSeperator) => { let currencyEl = document.getElementById(elementId); @@ -443,108 +443,108 @@ window.blazorBootstrap = { bootstrap?.Dropdown?.getOrCreateInstance(dropdownEl)?.update(); } }, - googlemaps: { - addMarker: (elementId, marker, dotNetHelper) => { - let mapInstance = window.blazorBootstrap.googlemaps.get(elementId); - if (mapInstance) { - let map = mapInstance.map; - let clickable = mapInstance.clickable; - let _content; - - if (marker.pinElement) { - let _glyph; - - if (marker.pinElement.useIconFonts) { - const icon = document.createElement("div"); - icon.innerHTML = ``; - _glyph = icon; - } else { - _glyph = marker.pinElement.glyph; - } - - const pin = new google.maps.marker.PinElement({ - background: marker.pinElement.background, - borderColor: marker.pinElement.borderColor, - glyph: _glyph, - glyphColor: marker.pinElement.glyphColor, - scale: marker.pinElement.scale, - }); - _content = pin.element; - } - else if (marker.content) { - _content = document.createElement("div"); - _content.classList.add("bb-google-marker-content"); - _content.innerHTML = marker.content; - } + googlemaps: { + addMarker: (elementId, marker, dotNetHelper) => { + let mapInstance = window.blazorBootstrap.googlemaps.get(elementId); + if (mapInstance) { + let map = mapInstance.map; + let clickable = mapInstance.clickable; + let _content; + + if (marker.pinElement) { + let _glyph; + + if (marker.pinElement.useIconFonts) { + const icon = document.createElement("div"); + icon.innerHTML = ``; + _glyph = icon; + } else { + _glyph = marker.pinElement.glyph; + } + + const pin = new google.maps.marker.PinElement({ + background: marker.pinElement.background, + borderColor: marker.pinElement.borderColor, + glyph: _glyph, + glyphColor: marker.pinElement.glyphColor, + scale: marker.pinElement.scale, + }); + _content = pin.element; + } + else if (marker.content) { + _content = document.createElement("div"); + _content.classList.add("bb-google-marker-content"); + _content.innerHTML = marker.content; + } + + const markerEl = new google.maps.marker.AdvancedMarkerElement({ + map, + content: _content, + position: marker.position, + title: marker.title, + gmpClickable: clickable + }); - const markerEl = new google.maps.marker.AdvancedMarkerElement({ - map, - content: _content, - position: marker.position, - title: marker.title, - gmpClickable: clickable - }); + window.blazorBootstrap.googlemaps.markerEls[elementId].push(markerEl); + + // add a click listener for each marker, and set up the info window. + if (clickable) { + markerEl.addListener("click", ({ domEvent, latLng }) => { + const { target } = domEvent; + const infoWindow = new google.maps.InfoWindow(); + infoWindow.close(); + infoWindow.setContent(markerEl.title); + infoWindow.open(markerEl.map, markerEl); + dotNetHelper.invokeMethodAsync('OnMarkerClickJS', marker); + }); + } + } + }, + create: (elementId, map, zoom, center, markers, clickable) => { + window.blazorBootstrap.googlemaps.instances[elementId] = { + map: map, + zoom: zoom, + center: center, + markers: markers, + clickable: clickable + }; + }, + get: (elementId) => { + return window.blazorBootstrap.googlemaps.instances[elementId]; + }, + initialize: (elementId, zoom, center, markers, clickable, dotNetHelper) => { + window.blazorBootstrap.googlemaps.markerEls[elementId] = window.blazorBootstrap.googlemaps.markerEls[elementId] ?? []; - window.blazorBootstrap.googlemaps.markerEls[elementId].push(markerEl); - - // add a click listener for each marker, and set up the info window. - if (clickable) { - markerEl.addListener("click", ({ domEvent, latLng }) => { - const { target } = domEvent; - const infoWindow = new google.maps.InfoWindow(); - infoWindow.close(); - infoWindow.setContent(markerEl.title); - infoWindow.open(markerEl.map, markerEl); - dotNetHelper.invokeMethodAsync('OnMarkerClickJS', marker); - }); - } - } - }, - create: (elementId, map, zoom, center, markers, clickable) => { - window.blazorBootstrap.googlemaps.instances[elementId] = { - map: map, - zoom: zoom, - center: center, - markers: markers, - clickable: clickable - }; - }, - get: (elementId) => { - return window.blazorBootstrap.googlemaps.instances[elementId]; - }, - initialize: (elementId, zoom, center, markers, clickable, dotNetHelper) => { - window.blazorBootstrap.googlemaps.markerEls[elementId] = window.blazorBootstrap.googlemaps.markerEls[elementId] ?? []; + let mapOptions = { center: center, zoom: zoom, mapId: elementId }; + let map = new google.maps.Map(document.getElementById(elementId), mapOptions); - let mapOptions = { center: center, zoom: zoom, mapId: elementId }; - let map = new google.maps.Map(document.getElementById(elementId), mapOptions); + window.blazorBootstrap.googlemaps.create(elementId, map, zoom, center, markers, clickable); - window.blazorBootstrap.googlemaps.create(elementId, map, zoom, center, markers, clickable); + if (markers) { + for (const marker of markers) { + window.blazorBootstrap.googlemaps.addMarker(elementId, marker, dotNetHelper); + } + } + }, + instances: {}, + markerEls: {}, + updateMarkers: (elementId, markers, dotNetHelper) => { + let markerEls = window.blazorBootstrap.googlemaps.markerEls[elementId] ?? []; - if (markers) { - for (const marker of markers) { - window.blazorBootstrap.googlemaps.addMarker(elementId, marker, dotNetHelper); - } - } - }, - instances: {}, - markerEls: {}, - updateMarkers: (elementId, markers, dotNetHelper) => { - let markerEls = window.blazorBootstrap.googlemaps.markerEls[elementId] ?? []; - - // delete the markers - if (markerEls.length > 0) { - for (const markerEl of markerEls) { - markerEl.setMap(null); - } - } + // delete the markers + if (markerEls.length > 0) { + for (const markerEl of markerEls) { + markerEl.setMap(null); + } + } - if (markers) { - for (const marker of markers) { - window.blazorBootstrap.googlemaps.addMarker(elementId, marker, dotNetHelper); - } - } + if (markers) { + for (const marker of markers) { + window.blazorBootstrap.googlemaps.addMarker(elementId, marker, dotNetHelper); } - }, + } + } + }, grid: { checkOrUnCheckAll: (cssSelector, isChecked) => { let chkEls = document.querySelectorAll(cssSelector); @@ -736,7 +736,7 @@ window.blazorBootstrap = { } }, scriptLoader: { - initialize: (elementId, async, defer, scriptId, source, type, dotNetHelper) => { + initialize: (elementId, async, defer, scriptId, source, type, dotNetHelper) => { let scriptLoaderEl = document.getElementById(elementId); if (source.length === 0) { @@ -748,7 +748,7 @@ window.blazorBootstrap = { scriptEl.async = async; - scriptEl.defer = defer; + scriptEl.defer = defer; if (scriptId != null) scriptEl.id = scriptId;