diff --git a/.github/dependabot.yml b/.github/dependabot.yml
index 25835c2d..0089655d 100644
--- a/.github/dependabot.yml
+++ b/.github/dependabot.yml
@@ -4,4 +4,4 @@ updates:
directory: "/src/Cropper.Blazor"
target-branch: "dev" # Location of package manifests
schedule:
- interval: "weekly"
+ interval: "monthly"
diff --git a/README.md b/README.md
index f280a439..bf6c64c4 100644
--- a/README.md
+++ b/README.md
@@ -21,9 +21,11 @@
- [CropperBlazor.github.io/demo](https://CropperBlazor.github.io/demo)
## Prerequisites
-- Supported .NET versions
- - [.NET 7.0](https://dotnet.microsoft.com/download/dotnet/7.0) for versions greater than v1.1.0
- - [.NET 6.0](https://dotnet.microsoft.com/download/dotnet/6.0) for v1.0.x
+- Supported .NET 7.0, .NET 6.0 versions for these web platforms:
+ - Blazor WebAssembly
+ - Blazor Server
+ - Blazor Server Hybrid with MVC
+ - MAUI Blazor Hybrid
## Installation
diff --git a/src/Cropper.Blazor/Client/.config/dotnet-tools.json b/src/Cropper.Blazor/Client/.config/dotnet-tools.json
index 43057ad8..d8410c8d 100644
--- a/src/Cropper.Blazor/Client/.config/dotnet-tools.json
+++ b/src/Cropper.Blazor/Client/.config/dotnet-tools.json
@@ -3,7 +3,7 @@
"isRoot": true,
"tools": {
"excubo.webcompiler": {
- "version": "3.5.20",
+ "version": "3.5.54",
"commands": [
"webcompiler"
]
diff --git a/src/Cropper.Blazor/Client/Components/Docs/SectionContent.razor b/src/Cropper.Blazor/Client/Components/Docs/SectionContent.razor
index 0bf6ce6a..31be8b04 100644
--- a/src/Cropper.Blazor/Client/Components/Docs/SectionContent.razor
+++ b/src/Cropper.Blazor/Client/Components/Docs/SectionContent.razor
@@ -14,20 +14,31 @@
@if (Codes != null || ChildContent != null)
{
+
@if(Codes != null)
{
@foreach (var codefile in Codes)
{
- @codefile.title
+
+ @codefile.title
+
}
}
@if (HasCode && ChildContent != null)
{
-
- @(ShowCode ? "Hide code" : "Show code")
+
+ @(ShowCode ? "Hide code" : "Show code")
}
+
}
@if (ChildContent != null)
@@ -44,6 +55,11 @@
@CodeComponent(ActiveCode)
-
+
}
\ No newline at end of file
diff --git a/src/Cropper.Blazor/Client/Components/Docs/SectionContent.razor.cs b/src/Cropper.Blazor/Client/Components/Docs/SectionContent.razor.cs
index 4d3314e1..6d927df3 100644
--- a/src/Cropper.Blazor/Client/Components/Docs/SectionContent.razor.cs
+++ b/src/Cropper.Blazor/Client/Components/Docs/SectionContent.razor.cs
@@ -2,6 +2,7 @@
using Cropper.Blazor.Client.Models;
using Microsoft.AspNetCore.Components;
using MudBlazor;
+using MudBlazor.Services;
using MudBlazor.Utilities;
namespace Cropper.Blazor.Client.Components.Docs;
@@ -9,6 +10,7 @@ namespace Cropper.Blazor.Client.Components.Docs;
public partial class SectionContent
{
[Inject] protected IJsApiService? JsApiService { get; set; }
+ [Inject] IBreakpointService BreakpointService { get; set; } = null!;
protected string Classname =>
new CssBuilder("docs-section-content")
@@ -17,6 +19,7 @@ public partial class SectionContent
.AddClass("show-code", HasCode && ShowCode)
.AddClass(Class)
.Build();
+
protected string ToolbarClassname =>
new CssBuilder("docs-section-content-toolbar")
.AddClass($"outlined", Outlined && ChildContent != null)
@@ -50,7 +53,9 @@ public partial class SectionContent
[Parameter] public RenderFragment ChildContent { get; set; }
private bool HasCode;
- private string ActiveCode;
+ public string ActiveCode;
+
+ private bool IsVerticalAlign = false;
protected override void OnParametersSet()
{
@@ -59,13 +64,27 @@ protected override void OnParametersSet()
HasCode = true;
ActiveCode = Codes.FirstOrDefault().code;
}
- else if (!String.IsNullOrWhiteSpace(Code))
+ else if (!string.IsNullOrWhiteSpace(Code))
{
HasCode = true;
ActiveCode = Code;
}
}
+ protected override async Task OnAfterRenderAsync(bool firstRender)
+ {
+ if (firstRender)
+ {
+ await BreakpointService!.SubscribeAsync((br) =>
+ {
+ IsVerticalAlign = BreakpointService!.IsMediaSize(br, Breakpoint.Xs);
+ InvokeAsync(StateHasChanged);
+ });
+ }
+
+ await base.OnAfterRenderAsync(firstRender);
+ }
+
public void OnShowCode()
{
ShowCode = !ShowCode;
@@ -88,9 +107,9 @@ private string GetActiveCode(string value)
}
}
- private async Task CopyTextToClipboard()
+ private async Task CopyTextToClipboardAsync()
{
- await JsApiService.CopyToClipboardAsync(Snippets.GetCode(string.IsNullOrWhiteSpace(Code) ? ActiveCode : Code));
+ await JsApiService!.CopyToClipboardAsync(Snippets.GetCode(string.IsNullOrWhiteSpace(Code) ? ActiveCode : Code));
}
RenderFragment CodeComponent(string code) => builder =>
diff --git a/src/Cropper.Blazor/Client/Cropper.Blazor.Client.csproj b/src/Cropper.Blazor/Client/Cropper.Blazor.Client.csproj
index 0ebddae2..ee7b3d0a 100644
--- a/src/Cropper.Blazor/Client/Cropper.Blazor.Client.csproj
+++ b/src/Cropper.Blazor/Client/Cropper.Blazor.Client.csproj
@@ -31,7 +31,7 @@
-
+
@@ -105,6 +105,7 @@
+
@@ -123,6 +124,7 @@
+
@@ -132,6 +134,7 @@
+
@@ -139,6 +142,7 @@
+
diff --git a/src/Cropper.Blazor/Client/Enums/CropperFace.cs b/src/Cropper.Blazor/Client/Enums/CropperFace.cs
new file mode 100644
index 00000000..f3a700bd
--- /dev/null
+++ b/src/Cropper.Blazor/Client/Enums/CropperFace.cs
@@ -0,0 +1,11 @@
+namespace Cropper.Blazor.Client.Enums
+{
+ public enum CropperFace
+ {
+ Default,
+ Close,
+ Pentagon,
+ Circle,
+ Arrow
+ }
+}
diff --git a/src/Cropper.Blazor/Client/Extensions/DocsVeiewExtension.cs b/src/Cropper.Blazor/Client/Extensions/DocsVeiewExtension.cs
index f2e9eab1..3ff7de2b 100644
--- a/src/Cropper.Blazor/Client/Extensions/DocsVeiewExtension.cs
+++ b/src/Cropper.Blazor/Client/Extensions/DocsVeiewExtension.cs
@@ -11,13 +11,13 @@ public static void TryAddDocsViewServices(this IServiceCollection services)
{
services.AddMudServices(config =>
{
- config.SnackbarConfiguration.PositionClass = Defaults.Classes.Position.BottomLeft;
+ config.SnackbarConfiguration.PositionClass = Defaults.Classes.Position.BottomRight;
config.SnackbarConfiguration.PreventDuplicates = false;
config.SnackbarConfiguration.NewestOnTop = false;
config.SnackbarConfiguration.ShowCloseIcon = true;
config.SnackbarConfiguration.VisibleStateDuration = 10000;
- config.SnackbarConfiguration.HideTransitionDuration = 500;
- config.SnackbarConfiguration.ShowTransitionDuration = 500;
+ config.SnackbarConfiguration.HideTransitionDuration = 200;
+ config.SnackbarConfiguration.ShowTransitionDuration = 100;
config.SnackbarConfiguration.SnackbarVariant = Variant.Filled;
});
diff --git a/src/Cropper.Blazor/Client/Pages/CropperDemo.razor b/src/Cropper.Blazor/Client/Pages/CropperDemo.razor
index 868706a2..9577a519 100644
--- a/src/Cropper.Blazor/Client/Pages/CropperDemo.razor
+++ b/src/Cropper.Blazor/Client/Pages/CropperDemo.razor
@@ -9,7 +9,7 @@
@*//---Cropper Component---//*@
-
+
@@ -160,20 +160,26 @@
Scale (-2, -1)
-
+
- Get Cropped Canvas
+ Get Cropped Canvas by URL
+
+
+
+
+ Get Cropped Canvas by element
-
+
320×180
-
-
+
+
640×360
@@ -243,6 +249,56 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GET
+
+
+
@@ -303,6 +359,56 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GET
+
+
+
diff --git a/src/Cropper.Blazor/Client/Pages/CropperDemo.razor.cs b/src/Cropper.Blazor/Client/Pages/CropperDemo.razor.cs
index 51280a39..208dfc1b 100644
--- a/src/Cropper.Blazor/Client/Pages/CropperDemo.razor.cs
+++ b/src/Cropper.Blazor/Client/Pages/CropperDemo.razor.cs
@@ -1,6 +1,7 @@
using System.Reflection;
using System.Text.Json;
using Cropper.Blazor.Client.Components;
+using Cropper.Blazor.Client.Enums;
using Cropper.Blazor.Components;
using Cropper.Blazor.Events;
using Cropper.Blazor.Events.CropEndEvent;
@@ -29,6 +30,7 @@ public partial class CropperDemo : IDisposable
private CropperDataPreview? CropperDataPreview = null!;
private GetSetCropperData? GetSetCropperData = null!;
private Options Options = null!;
+ private CropperFace CropperFace = CropperFace.Default;
private decimal? ScaleXValue;
private decimal? ScaleYValue;
private decimal AspectRatio = 1.7777777777777777m;
@@ -40,6 +42,10 @@ public partial class CropperDemo : IDisposable
private readonly string _errorLoadImageSrc = "not-found-image.jpg";
private Breakpoint Start;
private Guid SubscriptionId;
+ private ElementReference ElementReferencePreviewLg;
+ private ElementReference ElementReferencePreviewMd;
+ private ElementReference ElementReferencePreviewSm;
+ private ElementReference ElementReferencePreviewXs;
public Dictionary InputAttributes { get; set; } =
new Dictionary()
@@ -52,12 +58,26 @@ protected override void OnInitialized()
{
Options = new Options()
{
- Preview = ".img-preview",
+ //Preview = ".img-preview",
AspectRatio = (decimal)16 / 9,
ViewMode = ViewMode.Vm0
};
}
+ protected override void OnAfterRender(bool firstRender)
+ {
+ if (firstRender)
+ {
+ Options.Preview = new ElementReference[]
+ {
+ ElementReferencePreviewXs,
+ ElementReferencePreviewSm,
+ ElementReferencePreviewMd,
+ ElementReferencePreviewLg
+ };
+ }
+ }
+
public async void OnCropEvent(JSEventData cropJSEvent)
{
if (cropJSEvent?.Detail is not null)
@@ -313,16 +333,40 @@ private void Reset()
public async void GetCroppedCanvasDataURL(GetCroppedCanvasOptions getCroppedCanvasOptions)
{
- //CroppedCanvas croppedCanvas = await cropperComponent!.GetCroppedCanvasAsync(getCroppedCanvasOptions);
- //string croppedCanvasDataURL = await croppedCanvas!.JSRuntimeObjectRef.InvokeAsync("toDataURL");
-
string croppedCanvasDataURL = await CropperComponent!.GetCroppedCanvasDataURLAsync(getCroppedCanvasOptions);
- DialogParameters parameters = new()
+
+ OpenCroppedCanvasDialog(croppedCanvasDataURL);
+ }
+
+ public async void GetCroppedCanvasData(GetCroppedCanvasOptions getCroppedCanvasOptions)
+ {
+ CroppedCanvas croppedCanvas = await CropperComponent!.GetCroppedCanvasAsync(getCroppedCanvasOptions);
+ string croppedCanvasDataURL = await croppedCanvas!.JSRuntimeObjectRef.InvokeAsync("toDataURL", "image/png", 1);
+
+ OpenCroppedCanvasDialog(croppedCanvasDataURL);
+ }
+
+ public async void GetCroppedCanvasDataByPolygonFilter(GetCroppedCanvasOptions getCroppedCanvasOptions)
+ {
+ CroppedCanvas croppedCanvas = await CropperComponent!.GetCroppedCanvasAsync(getCroppedCanvasOptions);
+ string croppedCanvasDataURL;
+
+ if (CropperFace == CropperFace.Default)
{
- { "Src", croppedCanvasDataURL }
- };
- var options = new DialogOptions() { CloseButton = true, MaxWidth = MaxWidth.Medium, FullWidth = true, DisableBackdropClick = true };
- _dialogService.Show("CroppedCanvasDialog", parameters, options);
+ croppedCanvasDataURL = await croppedCanvas!.JSRuntimeObjectRef.InvokeAsync("toDataURL", "image/png", 1);
+ }
+ else if (CropperFace == CropperFace.Circle)
+ {
+ croppedCanvasDataURL = await JSRuntime!.InvokeAsync("window.addClipPathEllipse", croppedCanvas!.JSRuntimeObjectRef);
+ }
+ else
+ {
+ IEnumerable croppedPathToCanvasCropper = GetCroppedPathToCanvasCropper();
+
+ croppedCanvasDataURL = await JSRuntime!.InvokeAsync("window.addClipPathPolygon", croppedCanvas!.JSRuntimeObjectRef, croppedPathToCanvasCropper);
+ }
+
+ OpenCroppedCanvasDialog(croppedCanvasDataURL);
}
public async Task InputFileChangeAsync(InputFileChangeEventArgs inputFileChangeEventArgs)
@@ -443,6 +487,50 @@ public void Dispose()
GC.SuppressFinalize(this);
}
+ public void SetCropperFace(CropperFace cropperFace)
+ {
+ CropperFace = cropperFace;
+ }
+
+ public string GetClassNameCropper() =>
+ "img-container" + CropperFace switch
+ {
+ CropperFace.Default => string.Empty,
+ CropperFace.Close => " cropper-face-close",
+ CropperFace.Pentagon => " cropper-face-pentagon",
+ CropperFace.Circle => " cropper-face-circle",
+ CropperFace.Arrow => " cropper-face-arrow",
+ _ => string.Empty,
+ };
+
+ public IEnumerable GetCroppedPathToCanvasCropper() =>
+ CropperFace switch
+ {
+ // That enumerable is equivalent css like that (the same for another paths) - clip-path: polygon(20% 0%, 0% 20%, 30% 50%, 0% 80%, 20% 100%, 50% 70%, 80% 100%, 100% 80%, 70% 50%, 100% 20%, 80% 0%, 50% 30%);
+ CropperFace.Close => new List { 20, 0, 0, 20, 30, 50, 0, 80, 20, 100, 50, 70, 80, 100, 100, 80, 70, 50, 100, 20, 80, 0, 50, 30 },
+ CropperFace.Pentagon => new List { 50, 0, 100, 38, 82, 100, 18, 100, 0, 38 },
+ CropperFace.Arrow => new List { 40, 0, 40, 40, 100, 40, 100, 60, 40, 60, 40, 100, 0, 50 },
+ _ => throw new InvalidOperationException()
+ };
+
+ private void OpenCroppedCanvasDialog(string croppedCanvasDataURL)
+ {
+ DialogParameters parameters = new()
+ {
+ { "Src", croppedCanvasDataURL }
+ };
+
+ DialogOptions options = new()
+ {
+ CloseButton = true,
+ MaxWidth = MaxWidth.Medium,
+ FullWidth = true,
+ DisableBackdropClick = true
+ };
+
+ _dialogService.Show("CroppedCanvasDialog", parameters, options);
+ }
+
protected virtual void Dispose(bool disposing)
{
if (disposing)
diff --git a/src/Cropper.Blazor/Client/Pages/Examples/InstallServicesForBlazorServerExample.razor b/src/Cropper.Blazor/Client/Pages/Examples/Installation/InstallServicesForBlazorServerExample.razor
similarity index 100%
rename from src/Cropper.Blazor/Client/Pages/Examples/InstallServicesForBlazorServerExample.razor
rename to src/Cropper.Blazor/Client/Pages/Examples/Installation/InstallServicesForBlazorServerExample.razor
diff --git a/src/Cropper.Blazor/Client/Pages/Examples/InstallServicesForBlazorServerExampleCode.html b/src/Cropper.Blazor/Client/Pages/Examples/Installation/InstallServicesForBlazorServerExampleCode.html
similarity index 100%
rename from src/Cropper.Blazor/Client/Pages/Examples/InstallServicesForBlazorServerExampleCode.html
rename to src/Cropper.Blazor/Client/Pages/Examples/Installation/InstallServicesForBlazorServerExampleCode.html
diff --git a/src/Cropper.Blazor/Client/Pages/Examples/InstallationManualComponentsExample.razor b/src/Cropper.Blazor/Client/Pages/Examples/Installation/InstallationManualComponentsExample.razor
similarity index 100%
rename from src/Cropper.Blazor/Client/Pages/Examples/InstallationManualComponentsExample.razor
rename to src/Cropper.Blazor/Client/Pages/Examples/Installation/InstallationManualComponentsExample.razor
diff --git a/src/Cropper.Blazor/Client/Pages/Examples/InstallationManualComponentsExampleCode.html b/src/Cropper.Blazor/Client/Pages/Examples/Installation/InstallationManualComponentsExampleCode.html
similarity index 75%
rename from src/Cropper.Blazor/Client/Pages/Examples/InstallationManualComponentsExampleCode.html
rename to src/Cropper.Blazor/Client/Pages/Examples/Installation/InstallationManualComponentsExampleCode.html
index f497f1ce..9b30e4fc 100644
--- a/src/Cropper.Blazor/Client/Pages/Examples/InstallationManualComponentsExampleCode.html
+++ b/src/Cropper.Blazor/Client/Pages/Examples/Installation/InstallationManualComponentsExampleCode.html
@@ -1,5 +1,6 @@
-
+
+
@using Cropper.Blazor.Components;
< CropperComponent
@@ -7,5 +8,18 @@
Src = " cropperblazor.png "
Options = " Blazor.Models.Options() "
/>
-
+
+
+
+
+
+
+
+.cropper-example {
+ max-height: 300px;
+ width: 100%;
+}
+
+
+
diff --git a/src/Cropper.Blazor/Client/Pages/Examples/InstallationManualCssFontsExample.razor b/src/Cropper.Blazor/Client/Pages/Examples/Installation/InstallationManualCssFontsExample.razor
similarity index 100%
rename from src/Cropper.Blazor/Client/Pages/Examples/InstallationManualCssFontsExample.razor
rename to src/Cropper.Blazor/Client/Pages/Examples/Installation/InstallationManualCssFontsExample.razor
diff --git a/src/Cropper.Blazor/Client/Pages/Examples/InstallationManualCssFontsExampleCode.html b/src/Cropper.Blazor/Client/Pages/Examples/Installation/InstallationManualCssFontsExampleCode.html
similarity index 100%
rename from src/Cropper.Blazor/Client/Pages/Examples/InstallationManualCssFontsExampleCode.html
rename to src/Cropper.Blazor/Client/Pages/Examples/Installation/InstallationManualCssFontsExampleCode.html
diff --git a/src/Cropper.Blazor/Client/Pages/Examples/InstallationManualImportsExample.razor b/src/Cropper.Blazor/Client/Pages/Examples/Installation/InstallationManualImportsExample.razor
similarity index 100%
rename from src/Cropper.Blazor/Client/Pages/Examples/InstallationManualImportsExample.razor
rename to src/Cropper.Blazor/Client/Pages/Examples/Installation/InstallationManualImportsExample.razor
diff --git a/src/Cropper.Blazor/Client/Pages/Examples/InstallationManualImportsExampleCode.html b/src/Cropper.Blazor/Client/Pages/Examples/Installation/InstallationManualImportsExampleCode.html
similarity index 100%
rename from src/Cropper.Blazor/Client/Pages/Examples/InstallationManualImportsExampleCode.html
rename to src/Cropper.Blazor/Client/Pages/Examples/Installation/InstallationManualImportsExampleCode.html
diff --git a/src/Cropper.Blazor/Client/Pages/Examples/InstallationManualPackageExample.razor b/src/Cropper.Blazor/Client/Pages/Examples/Installation/InstallationManualPackageExample.razor
similarity index 100%
rename from src/Cropper.Blazor/Client/Pages/Examples/InstallationManualPackageExample.razor
rename to src/Cropper.Blazor/Client/Pages/Examples/Installation/InstallationManualPackageExample.razor
diff --git a/src/Cropper.Blazor/Client/Pages/Examples/InstallationManualPackageExampleCode.html b/src/Cropper.Blazor/Client/Pages/Examples/Installation/InstallationManualPackageExampleCode.html
similarity index 100%
rename from src/Cropper.Blazor/Client/Pages/Examples/InstallationManualPackageExampleCode.html
rename to src/Cropper.Blazor/Client/Pages/Examples/Installation/InstallationManualPackageExampleCode.html
diff --git a/src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromElementReferenceSelectorComponentsExample.razor b/src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromElementReferenceSelectorComponentsExample.razor
new file mode 100644
index 00000000..5730dad3
--- /dev/null
+++ b/src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromElementReferenceSelectorComponentsExample.razor
@@ -0,0 +1,25 @@
+@using Cropper.Blazor.Components
+
+
+
+
+
+
+@code {
+ private Blazor.Models.Options Options = new();
+ private ElementReference ElementReference;
+
+ protected override void OnAfterRender(bool firstRender)
+ {
+ if (firstRender)
+ {
+ Options.Preview = new ElementReference[]
+ {
+ ElementReference
+ };
+ }
+ }
+}
diff --git a/src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromElementReferenceSelectorComponentsExample.razor.css b/src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromElementReferenceSelectorComponentsExample.razor.css
new file mode 100644
index 00000000..515e4e8c
--- /dev/null
+++ b/src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromElementReferenceSelectorComponentsExample.razor.css
@@ -0,0 +1,14 @@
+.cropper-example {
+ max-height: 300px;
+ width: 100%;
+}
+
+.img-example-preview {
+ width: 100%;
+ height: 300px;
+ overflow: hidden;
+}
+
+.img-example-preview > ::deep img {
+ max-width: 100%;
+}
diff --git a/src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromElementReferenceSelectorComponentsExampleCode.html b/src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromElementReferenceSelectorComponentsExampleCode.html
new file mode 100644
index 00000000..343478c0
--- /dev/null
+++ b/src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromElementReferenceSelectorComponentsExampleCode.html
@@ -0,0 +1,54 @@
+
+
+
+@using Cropper.Blazor.Components;
+
+< div class = " img-container "
+ < CropperComponent
+ Class = " cropper-example "
+ Src = " cropperblazor.png "
+ Options = " Options "
+ />
+</div >
+< div @ref = " ElementReference " class = " img-example-preview " />
+
+@ code {
+ private Blazor.Models.Options Options = new ();
+ private Microsoft.AspNetCore.Components.ElementReference ElementReference;
+
+ protected override void OnAfterRender (bool firstRender )
+ {
+ if (firstRender )
+ {
+ Options .Preview = new ElementReference []
+ {
+ ElementReference
+ };
+ }
+ }
+}
+
+
+
+
+
+
+
+.cropper-example {
+ max-height: 300px;
+ width: 100%;
+}
+
+.img-example-preview {
+ width: 100%;
+ height: 300px;
+ overflow: hidden;
+}
+
+.img-example-preview > ::deep img {
+ max-width: 100%;
+}
+
+
+
+
diff --git a/src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromMultipleElementReferenceSelectorComponentsExample.razor b/src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromMultipleElementReferenceSelectorComponentsExample.razor
new file mode 100644
index 00000000..04395890
--- /dev/null
+++ b/src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromMultipleElementReferenceSelectorComponentsExample.razor
@@ -0,0 +1,25 @@
+@using Cropper.Blazor.Components
+
+
+
+
+
+
+
+@code {
+ private Blazor.Models.Options Options = new();
+ private ElementReference FirstElementReference;
+ private ElementReference SecondElementReference;
+
+ protected override void OnAfterRender(bool firstRender)
+ {
+ if (firstRender)
+ {
+ Options.Preview = new ElementReference[]
+ {
+ FirstElementReference,
+ SecondElementReference
+ };
+ }
+ }
+}
diff --git a/src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromMultipleElementReferenceSelectorComponentsExample.razor.css b/src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromMultipleElementReferenceSelectorComponentsExample.razor.css
new file mode 100644
index 00000000..515e4e8c
--- /dev/null
+++ b/src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromMultipleElementReferenceSelectorComponentsExample.razor.css
@@ -0,0 +1,14 @@
+.cropper-example {
+ max-height: 300px;
+ width: 100%;
+}
+
+.img-example-preview {
+ width: 100%;
+ height: 300px;
+ overflow: hidden;
+}
+
+.img-example-preview > ::deep img {
+ max-width: 100%;
+}
diff --git a/src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromMultipleElementReferenceSelectorComponentsExampleCode.html b/src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromMultipleElementReferenceSelectorComponentsExampleCode.html
new file mode 100644
index 00000000..97293bd9
--- /dev/null
+++ b/src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromMultipleElementReferenceSelectorComponentsExampleCode.html
@@ -0,0 +1,57 @@
+
+
+
+@using Cropper.Blazor.Components;
+
+< div class = " img-container "
+ < CropperComponent
+ Class = " cropper-example "
+ Src = " cropperblazor.png "
+ Options = " Options "
+ />
+</div >
+< div @ref = " FirstElementReference " class = " img-example-preview " />
+< div @ref = " SecondElementReference " class = " img-example-preview " />
+
+@ code {
+ private Blazor.Models.Options Options = new ();
+ private Microsoft.AspNetCore.Components.ElementReference FirstElementReference;
+ private Microsoft.AspNetCore.Components.ElementReference SecondElementReference;
+
+ protected override void OnAfterRender (bool firstRender )
+ {
+ if (firstRender )
+ {
+ Options .Preview = new ElementReference []
+ {
+ FirstElementReference,
+ SecondElementReference
+ };
+ }
+ }
+}
+
+
+
+
+
+
+
+.cropper-example {
+ max-height: 300px;
+ width: 100%;
+}
+
+.img-example-preview {
+ width: 100%;
+ height: 300px;
+ overflow: hidden;
+}
+
+.img-example-preview > ::deep img {
+ max-width: 100%;
+}
+
+
+
+
diff --git a/src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromStringSelectorComponentsExample.razor b/src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromStringSelectorComponentsExample.razor
new file mode 100644
index 00000000..13f4d5a9
--- /dev/null
+++ b/src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromStringSelectorComponentsExample.razor
@@ -0,0 +1,16 @@
+@using Cropper.Blazor.Components
+
+
+
+
+
+
+@code {
+ private Blazor.Models.Options Options = new Blazor.Models.Options
+ {
+ Preview = ".img-example-preview"
+ };
+}
diff --git a/src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromStringSelectorComponentsExample.razor.css b/src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromStringSelectorComponentsExample.razor.css
new file mode 100644
index 00000000..515e4e8c
--- /dev/null
+++ b/src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromStringSelectorComponentsExample.razor.css
@@ -0,0 +1,14 @@
+.cropper-example {
+ max-height: 300px;
+ width: 100%;
+}
+
+.img-example-preview {
+ width: 100%;
+ height: 300px;
+ overflow: hidden;
+}
+
+.img-example-preview > ::deep img {
+ max-width: 100%;
+}
diff --git a/src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromStringSelectorComponentsExampleCode.html b/src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromStringSelectorComponentsExampleCode.html
new file mode 100644
index 00000000..11f76130
--- /dev/null
+++ b/src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromStringSelectorComponentsExampleCode.html
@@ -0,0 +1,45 @@
+
+
+
+@using Cropper.Blazor.Components;
+
+< div class = " img-container "
+ < CropperComponent
+ Class = " cropper-example "
+ Src = " cropperblazor.png "
+ Options = " Options "
+ />
+</div >
+< div class = " img-example-preview " />
+
+@ code {
+ private Blazor.Models.Options Options = new Blazor.Models.Options
+ {
+ Preview = ".img-example-preview"
+ };
+}
+
+
+
+
+
+
+
+.cropper-example {
+ max-height: 300px;
+ width: 100%;
+}
+
+.img-example-preview {
+ width: 100%;
+ height: 300px;
+ overflow: hidden;
+}
+
+.img-example-preview > ::deep img {
+ max-width: 100%;
+}
+
+
+
+
diff --git a/src/Cropper.Blazor/Client/Pages/Index.razor b/src/Cropper.Blazor/Client/Pages/Index.razor
index 7defb1f2..7610889f 100644
--- a/src/Cropper.Blazor/Client/Pages/Index.razor
+++ b/src/Cropper.Blazor/Client/Pages/Index.razor
@@ -2,7 +2,8 @@
@using Cropper.Blazor.Client.Components
@using Cropper.Blazor.Client.Components.Docs
@using Cropper.Blazor.Client.Models;
-@using Cropper.Blazor.Client.Pages.Examples
+@using Cropper.Blazor.Client.Pages.Examples.Installation
+@using Cropper.Blazor.Client.Pages.Examples.Uses.Preview
@@ -22,8 +23,8 @@
- Cropper.Blazor
- is a component element that wraps around
+ Cropper.Blazor
+ is a component element that wraps around
Cropper.js
@@ -113,6 +114,27 @@
+
+
+ Add the following components to your MainLayout.razor
+
+ Notes for Preview Option:
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Cropper.Blazor/Client/Pages/Index.razor.cs b/src/Cropper.Blazor/Client/Pages/Index.razor.cs
new file mode 100644
index 00000000..d027320c
--- /dev/null
+++ b/src/Cropper.Blazor/Client/Pages/Index.razor.cs
@@ -0,0 +1,34 @@
+using Cropper.Blazor.Client.Components.Docs;
+using Cropper.Blazor.Client.Pages.Examples.Uses.Preview;
+using Microsoft.AspNetCore.Components;
+
+namespace Cropper.Blazor.Client.Pages
+{
+ public partial class Index
+ {
+ SectionContent ActivePreviewActive = null!;
+
+ RenderFragment PreviewActiveRenderFragment => builder =>
+ {
+ if (ActivePreviewActive.ActiveCode == nameof(UsesPreviewFromStringSelectorComponentsExample))
+ {
+ builder.OpenComponent(1);
+ builder.CloseComponent();
+ }
+ else if (ActivePreviewActive.ActiveCode == nameof(UsesPreviewFromElementReferenceSelectorComponentsExample))
+ {
+ builder.OpenComponent(1);
+ builder.CloseComponent();
+ }
+ else if (ActivePreviewActive.ActiveCode == nameof(UsesPreviewFromMultipleElementReferenceSelectorComponentsExample))
+ {
+ builder.OpenComponent(1);
+ builder.CloseComponent();
+ }
+ else
+ {
+ throw new InvalidOperationException();
+ }
+ };
+ }
+}
diff --git a/src/Cropper.Blazor/Client/Shared/MainLayout.razor b/src/Cropper.Blazor/Client/Shared/MainLayout.razor
index 15be5a99..7d03b584 100644
--- a/src/Cropper.Blazor/Client/Shared/MainLayout.razor
+++ b/src/Cropper.Blazor/Client/Shared/MainLayout.razor
@@ -4,6 +4,7 @@
+
diff --git a/src/Cropper.Blazor/Client/Shared/UpdateAvailableDetector.razor b/src/Cropper.Blazor/Client/Shared/UpdateAvailableDetector.razor
new file mode 100644
index 00000000..8b137891
--- /dev/null
+++ b/src/Cropper.Blazor/Client/Shared/UpdateAvailableDetector.razor
@@ -0,0 +1 @@
+
diff --git a/src/Cropper.Blazor/Client/Shared/UpdateAvailableDetector.razor.cs b/src/Cropper.Blazor/Client/Shared/UpdateAvailableDetector.razor.cs
new file mode 100644
index 00000000..3d7dd439
--- /dev/null
+++ b/src/Cropper.Blazor/Client/Shared/UpdateAvailableDetector.razor.cs
@@ -0,0 +1,45 @@
+using Microsoft.AspNetCore.Components;
+using Microsoft.JSInterop;
+using MudBlazor;
+
+namespace Cropper.Blazor.Client.Shared
+{
+ public partial class UpdateAvailableDetector
+ {
+ [Inject] private IJSRuntime? JSRuntime { get; set; }
+ [Inject] private ISnackbar? Snackbar { get; set; }
+ [Inject] private NavigationManager? Navigation { get; set; }
+
+ protected override async Task OnInitializedAsync()
+ {
+ await RegisterForUpdateAvailableNotification();
+ }
+
+ private async Task RegisterForUpdateAvailableNotification()
+ {
+ await JSRuntime!.InvokeAsync(
+ identifier: "registerForUpdateAvailableNotification",
+ DotNetObjectReference.Create(this),
+ nameof(OnUpdateAvailable));
+ }
+
+ [JSInvokable(nameof(OnUpdateAvailable))]
+ public void OnUpdateAvailable()
+ {
+ Snackbar!.Add("A new version of the application is available.", Severity.Warning, config =>
+ {
+ config.Action = "Reload";
+ config.IconColor = Color.Error;
+ config.ActionColor = Color.Error;
+ config.Icon = Icons.Material.Filled.BrowserUpdated;
+ config.RequireInteraction = true;
+ config.Onclick = snackbar =>
+ {
+ Navigation!.NavigateTo(Navigation.Uri, true);
+
+ return Task.CompletedTask;
+ };
+ });
+ }
+ }
+}
diff --git a/src/Cropper.Blazor/Client/Styles/Cropper.Blazor.Client.scss b/src/Cropper.Blazor/Client/Styles/Cropper.Blazor.Client.scss
index 09abc5ab..6179f399 100644
--- a/src/Cropper.Blazor/Client/Styles/Cropper.Blazor.Client.scss
+++ b/src/Cropper.Blazor/Client/Styles/Cropper.Blazor.Client.scss
@@ -1,5 +1,6 @@
@import 'layout/_mainlayout';
@import 'layout/_markdown';
+@import 'layout/_updateAvaibleDetector.scss';
@import 'components/docssection.scss';
.no-select {
@@ -117,3 +118,23 @@ html, body {
.cropped-canvas-dialog .mud-dialog-title {
padding-bottom: 0;
}
+
+.cropper-face {
+ opacity: 25%;
+}
+
+.img-container.cropper-face-close .cropper-container .cropper-crop-box .cropper-face {
+ clip-path: polygon(20% 0%, 0% 20%, 30% 50%, 0% 80%, 20% 100%, 50% 70%, 80% 100%, 100% 80%, 70% 50%, 100% 20%, 80% 0%, 50% 30%);
+}
+
+.img-container.cropper-face-arrow .cropper-container .cropper-crop-box .cropper-face {
+ clip-path: polygon(40% 0%, 40% 40%, 100% 40%, 100% 60%, 40% 60%, 40% 100%, 0% 50%);
+}
+
+.img-container.cropper-face-circle .cropper-container .cropper-crop-box .cropper-face {
+ border-radius: 50%;
+}
+
+.img-container.cropper-face-pentagon .cropper-container .cropper-crop-box .cropper-face {
+ clip-path: polygon(50% 0%, 100% 38%, 82% 100%, 18% 100%, 0% 38%);
+}
diff --git a/src/Cropper.Blazor/Client/Styles/layout/_markdown.scss b/src/Cropper.Blazor/Client/Styles/layout/_markdown.scss
index ed250cab..3f0602b2 100644
--- a/src/Cropper.Blazor/Client/Styles/layout/_markdown.scss
+++ b/src/Cropper.Blazor/Client/Styles/layout/_markdown.scss
@@ -109,6 +109,16 @@
direction: ltr;
}
+ & .css {
+ & .property {
+ color: hsl(76, 21%, 52%);
+ }
+
+ & .comment {
+ color: #57a64a;
+ }
+ }
+
& .csharp {
& .atSign {
color: var(--mud-palette-text-primary);
diff --git a/src/Cropper.Blazor/Client/Styles/layout/_updateAvaibleDetector.scss b/src/Cropper.Blazor/Client/Styles/layout/_updateAvaibleDetector.scss
new file mode 100644
index 00000000..2291b4c9
--- /dev/null
+++ b/src/Cropper.Blazor/Client/Styles/layout/_updateAvaibleDetector.scss
@@ -0,0 +1,5 @@
+@media (min-width: 0) and (max-width: 510px) {
+ .mud-snackbar-location-bottom-right {
+ right: 0 !important;
+ }
+}
diff --git a/src/Cropper.Blazor/Client/wwwroot/helper.js b/src/Cropper.Blazor/Client/wwwroot/helper.js
index b4af1b2a..59ad08a5 100644
--- a/src/Cropper.Blazor/Client/wwwroot/helper.js
+++ b/src/Cropper.Blazor/Client/wwwroot/helper.js
@@ -4,4 +4,50 @@
anchorElement.download = options.fileName ?? '';
anchorElement.click();
anchorElement.remove();
-};
\ No newline at end of file
+};
+
+window.addClipPathPolygon = (sourceCanvas, path) => {
+ const canvas = document.createElement('canvas');
+ const context = canvas.getContext('2d');
+ const width = sourceCanvas.width,
+ height = sourceCanvas.height;
+
+ canvas.width = width;
+ canvas.height = height;
+ context.imageSmoothingEnabled = true;
+
+ context.beginPath();
+ context.moveTo(path[0] * width / 100, path[1] * height / 100);
+ context.fillStyle = "rgba(255, 255, 255, 0)";
+
+ for (let i = 2; i < path.length; i += 2) {
+ context.lineTo(path[i] * width / 100, path[i + 1] * height / 100);
+ }
+
+ context.closePath();
+ context.clip();
+ context.fill();
+ context.globalCompositeOperation = 'lighter';
+ context.drawImage(sourceCanvas, 0, 0, width, height);
+
+ return canvas.toDataURL("image/png", 1);
+}
+
+window.addClipPathEllipse = (sourceCanvas) => {
+ const createdCanvas = document.createElement('canvas');
+ const contextCanvas = createdCanvas.getContext('2d');
+ const widthCanvas = sourceCanvas.width,
+ heightCanvas = sourceCanvas.height;
+
+ createdCanvas.width = widthCanvas;
+ createdCanvas.height = heightCanvas;
+ contextCanvas.imageSmoothingEnabled = true;
+
+ contextCanvas.drawImage(sourceCanvas, 0, 0, widthCanvas, heightCanvas);
+ contextCanvas.globalCompositeOperation = 'destination-in';
+ contextCanvas.beginPath();
+ contextCanvas.ellipse(widthCanvas / 2, heightCanvas / 2, widthCanvas / 2, heightCanvas / 2, 0 * Math.PI, 0, 180 * Math.PI, true);
+ contextCanvas.fill();
+
+ return createdCanvas.toDataURL("image/png", 1);
+}
diff --git a/src/Cropper.Blazor/Client/wwwroot/index.html b/src/Cropper.Blazor/Client/wwwroot/index.html
index ca7e8df9..15d27955 100644
--- a/src/Cropper.Blazor/Client/wwwroot/index.html
+++ b/src/Cropper.Blazor/Client/wwwroot/index.html
@@ -131,7 +131,7 @@
-
+