mirror of
https://github.com/radzenhq/radzen-blazor.git
synced 2026-02-04 05:35:44 +00:00
Compare commits
268 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6f16f230d1 | ||
|
|
f458a057e8 | ||
|
|
d013300fa3 | ||
|
|
d6b8394044 | ||
|
|
c1fa630602 | ||
|
|
28a03dadaf | ||
|
|
29cfc2ea6b | ||
|
|
f4c776f10e | ||
|
|
04be6bc38b | ||
|
|
4f0bbeeab0 | ||
|
|
5a356a8d75 | ||
|
|
7f35f46eaa | ||
|
|
ea7be67d83 | ||
|
|
8f0d65766d | ||
|
|
a140f318a2 | ||
|
|
d0a2d1644f | ||
|
|
e69b153e1c | ||
|
|
d19d383738 | ||
|
|
253f288323 | ||
|
|
d6ce0536ca | ||
|
|
0168c01915 | ||
|
|
7329fec67a | ||
|
|
5fea22294e | ||
|
|
669124a6b3 | ||
|
|
c44d141c07 | ||
|
|
0b30e00b8c | ||
|
|
1e7bd1bf48 | ||
|
|
c2c4d6aa02 | ||
|
|
7e0c64191c | ||
|
|
323e4e971a | ||
|
|
99b4f8f8fc | ||
|
|
7c1cf76c5c | ||
|
|
305e1b7af6 | ||
|
|
6880a70227 | ||
|
|
0482969755 | ||
|
|
4c9b429dae | ||
|
|
60b8400e29 | ||
|
|
7260be98d6 | ||
|
|
be94094de7 | ||
|
|
645077f39b | ||
|
|
b42940441d | ||
|
|
fc7071c04e | ||
|
|
de887a4e3f | ||
|
|
7f629309c7 | ||
|
|
fa45e209d5 | ||
|
|
40aec6cd0d | ||
|
|
969ae7aeca | ||
|
|
a64bbd34f3 | ||
|
|
79acf83d6f | ||
|
|
786e8d0be1 | ||
|
|
2757850f28 | ||
|
|
7c6f39f3b5 | ||
|
|
70723d0437 | ||
|
|
bd9b0f798b | ||
|
|
0c406b2ad8 | ||
|
|
822891541c | ||
|
|
bf064fd4e3 | ||
|
|
6c9e055d42 | ||
|
|
7455d1bfb2 | ||
|
|
7b923b6625 | ||
|
|
bcd18e9395 | ||
|
|
082d577834 | ||
|
|
68bf4f9df3 | ||
|
|
9348698aac | ||
|
|
979025f7d9 | ||
|
|
9aa09050da | ||
|
|
f331de4185 | ||
|
|
1ce067c854 | ||
|
|
e6d537f0f8 | ||
|
|
6a69a8d21a | ||
|
|
415cc09a06 | ||
|
|
fb482e133e | ||
|
|
c8134ce2ec | ||
|
|
a59c062dda | ||
|
|
fe604d3439 | ||
|
|
53ad8466ad | ||
|
|
9e3c844231 | ||
|
|
85a10e7c72 | ||
|
|
902dc5bdd1 | ||
|
|
666cbc9e47 | ||
|
|
745fae3f76 | ||
|
|
bb2c4d4c3f | ||
|
|
f8c8d6725c | ||
|
|
54747dc800 | ||
|
|
63b6c0cab4 | ||
|
|
92c85a0791 | ||
|
|
83f47bfe6e | ||
|
|
2f034e98c0 | ||
|
|
cb416c3583 | ||
|
|
584353a240 | ||
|
|
729456c2a0 | ||
|
|
a02a2e5332 | ||
|
|
78f0204d86 | ||
|
|
b76ef5ca80 | ||
|
|
788fc01cfb | ||
|
|
4dc9360b34 | ||
|
|
6c0e1b7f01 | ||
|
|
27b91642f2 | ||
|
|
0c7be4b2c7 | ||
|
|
e41ba71828 | ||
|
|
2b2b6b98f1 | ||
|
|
8f6b20abd1 | ||
|
|
21a69c4a61 | ||
|
|
e7b671283a | ||
|
|
d46a7a50b5 | ||
|
|
dfae4e0848 | ||
|
|
a0f7e924e5 | ||
|
|
fd2f3c7dbe | ||
|
|
da442dc02b | ||
|
|
eaea900100 | ||
|
|
449662f858 | ||
|
|
def2219f41 | ||
|
|
4670fc477d | ||
|
|
cea4572843 | ||
|
|
b769d4644a | ||
|
|
3d9b117a74 | ||
|
|
3b1a5f227e | ||
|
|
a66a2d936e | ||
|
|
8b5c334d47 | ||
|
|
5597cf6753 | ||
|
|
9d2d83d8d1 | ||
|
|
bc695479fa | ||
|
|
c0f7f2accd | ||
|
|
08309d6162 | ||
|
|
b217036ad0 | ||
|
|
a276652cbc | ||
|
|
39f643330a | ||
|
|
2967cc917c | ||
|
|
78d22b3165 | ||
|
|
989036bdf2 | ||
|
|
926e9ff92c | ||
|
|
4696567514 | ||
|
|
e153a30186 | ||
|
|
e8bbd3dace | ||
|
|
d2d1344858 | ||
|
|
6be828079d | ||
|
|
7a07a5c646 | ||
|
|
ee649ebeb9 | ||
|
|
67fe2a5a67 | ||
|
|
6ac193c139 | ||
|
|
b7492a6dfa | ||
|
|
224e86f673 | ||
|
|
f014e155d6 | ||
|
|
7aa37cd6cb | ||
|
|
b1cc09fcb6 | ||
|
|
4717293666 | ||
|
|
a80cd0720f | ||
|
|
e238676efc | ||
|
|
e1df231137 | ||
|
|
f40d10b35c | ||
|
|
ea20e5445e | ||
|
|
4a6f2dbdc3 | ||
|
|
11ff01bc61 | ||
|
|
2a292e6a82 | ||
|
|
dc11242b77 | ||
|
|
4ec8f5fc28 | ||
|
|
690f3ed87c | ||
|
|
04e8f6f2e3 | ||
|
|
e96ab86198 | ||
|
|
eae010a23b | ||
|
|
d9d829e37d | ||
|
|
53680fc774 | ||
|
|
46b8378297 | ||
|
|
a26b4f779e | ||
|
|
c2e8c87f3b | ||
|
|
c99e82bd8e | ||
|
|
1398e54896 | ||
|
|
2d93e5bb1c | ||
|
|
6b901d42f7 | ||
|
|
0cc8a968ed | ||
|
|
3f2914c6fa | ||
|
|
9e01786278 | ||
|
|
78ec625cd5 | ||
|
|
02855e3ac4 | ||
|
|
2fc65f135d | ||
|
|
88085ca5a6 | ||
|
|
fe26a82d66 | ||
|
|
e98678b1f7 | ||
|
|
ef2b4d785a | ||
|
|
b721f3e3ce | ||
|
|
13cc0fc08c | ||
|
|
65fe95d464 | ||
|
|
80a887b0d0 | ||
|
|
bed1915da4 | ||
|
|
65cde0af99 | ||
|
|
a0a2b8b265 | ||
|
|
ed01254c84 | ||
|
|
e03864ac03 | ||
|
|
83796c5aa4 | ||
|
|
0e329def1a | ||
|
|
27859cf183 | ||
|
|
5560e7ee3d | ||
|
|
72bab915b1 | ||
|
|
f5fefcdd55 | ||
|
|
160634ea38 | ||
|
|
50fb5a96d8 | ||
|
|
79c7ea16d8 | ||
|
|
a166db0ea1 | ||
|
|
2b905615d1 | ||
|
|
a18c1b5e0c | ||
|
|
c066043ceb | ||
|
|
41d64f1b7c | ||
|
|
36023fdc35 | ||
|
|
8437cf279d | ||
|
|
d2e19cf3c7 | ||
|
|
9a90be6e79 | ||
|
|
903a4c78e2 | ||
|
|
19049bfea8 | ||
|
|
0c4e92ebec | ||
|
|
aefe937adc | ||
|
|
63eda04815 | ||
|
|
18c7783942 | ||
|
|
6c17e1e9c5 | ||
|
|
955355460e | ||
|
|
51a110b9a3 | ||
|
|
43da6c3656 | ||
|
|
411c916a26 | ||
|
|
c0cc14ec99 | ||
|
|
4f8dd8844c | ||
|
|
36f8f43aad | ||
|
|
534d7f570e | ||
|
|
599e514afc | ||
|
|
42054827a2 | ||
|
|
bfe517ef75 | ||
|
|
c585f3455d | ||
|
|
fe1d3dd82b | ||
|
|
92d503335b | ||
|
|
782f93169d | ||
|
|
0c12177091 | ||
|
|
cc90ff97e3 | ||
|
|
525230cf2d | ||
|
|
2df9ef3fca | ||
|
|
9de1b6d9d2 | ||
|
|
94b096259a | ||
|
|
4e7011f12b | ||
|
|
ff123ddcb4 | ||
|
|
9d98fefdef | ||
|
|
573bddb1ae | ||
|
|
8386848e0e | ||
|
|
5ba0220a74 | ||
|
|
d24cadcf00 | ||
|
|
fbe53df424 | ||
|
|
eb0347073e | ||
|
|
45907bdcca | ||
|
|
b5b8aaf731 | ||
|
|
d4eb749729 | ||
|
|
3e09882b0c | ||
|
|
a443b57ead | ||
|
|
3a430b3586 | ||
|
|
f09f8ba4eb | ||
|
|
c6a1560a0f | ||
|
|
805f596f1f | ||
|
|
bcee601d4c | ||
|
|
ea009e802b | ||
|
|
e421eaaf1a | ||
|
|
997cd88db8 | ||
|
|
ccc8fbde05 | ||
|
|
0fdf7721a7 | ||
|
|
96f1863711 | ||
|
|
ea9c7543d9 | ||
|
|
b69a02c878 | ||
|
|
4d9c792a25 | ||
|
|
7a6992845a | ||
|
|
f2deb8f402 | ||
|
|
c067b162b9 | ||
|
|
f1415d7583 | ||
|
|
14f23e79f1 | ||
|
|
a5a55e207c |
26
.github/workflows/ci.yml
vendored
Normal file
26
.github/workflows/ci.yml
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
# This workflow will build a .NET project
|
||||
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-net
|
||||
|
||||
name: .NET
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "master" ]
|
||||
pull_request:
|
||||
branches: [ "master" ]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v3
|
||||
with:
|
||||
dotnet-version: 7.0.x
|
||||
- name: Build
|
||||
run: dotnet build Radzen.Blazor/Radzen.Blazor.csproj
|
||||
- name: Test
|
||||
run: dotnet test Radzen.Blazor.Tests/Radzen.Blazor.Tests.csproj
|
||||
@@ -19,7 +19,7 @@ You can ask your question here. Please use the [Radzen.Blazor Components](https:
|
||||
|
||||
### Dedicated technical support
|
||||
|
||||
Radzen staff provides technical support with guaranteed response time to Radzen Professional and Enterprise subscribers. The pricing options are available [here](https://www.radzen.com/pricing/).
|
||||
Radzen staff provides technical support with guaranteed response time to Radzen Professional and Enterprise subscribers. The pricing options are available [here](https://www.radzen.com/blazor-studio/pricing/).
|
||||
|
||||
## How Can I Contribute?
|
||||
|
||||
|
||||
13
Dockerfile
13
Dockerfile
@@ -13,18 +13,19 @@ RUN apt-get update && apt-get install unzip wget git -y && wget -q -P /tmp https
|
||||
COPY Radzen.Blazor /app/Radzen.Blazor
|
||||
COPY Radzen.DocFX /app/DocFX
|
||||
COPY RadzenBlazorDemos /app/RadzenBlazorDemos
|
||||
COPY RadzenBlazorDemos.Host /app/RadzenBlazorDemos.Host
|
||||
WORKDIR /app
|
||||
RUN docfx DocFX/docfx.json
|
||||
|
||||
FROM mcr.microsoft.com/dotnet/sdk:7.0
|
||||
|
||||
COPY --from=0 /app/RadzenBlazorDemos /app
|
||||
WORKDIR /app
|
||||
COPY --from=0 /app/RadzenBlazorDemos.Host /app/RadzenBlazorDemos.Host
|
||||
COPY --from=0 /app/RadzenBlazorDemos /app/RadzenBlazorDemos
|
||||
|
||||
WORKDIR /app/RadzenBlazorDemos.Host
|
||||
RUN dotnet publish -c Release -o out
|
||||
COPY RadzenBlazorDemos/northwind.db /app/out
|
||||
COPY RadzenBlazorDemos/northwind.sql /app/out
|
||||
|
||||
ENV ASPNETCORE_URLS http://*:5000
|
||||
WORKDIR /app/out
|
||||
WORKDIR /app/RadzenBlazorDemos.Host/out
|
||||
|
||||
ENTRYPOINT ["dotnet", "RadzenBlazorDemos.dll"]
|
||||
ENTRYPOINT ["dotnet", "RadzenBlazorDemos.Host.dll"]
|
||||
|
||||
2
LICENSE
2
LICENSE
@@ -1,6 +1,6 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2018-2022 Radzen Ltd
|
||||
Copyright (c) 2018-2023 Radzen Ltd
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
15
README.md
15
README.md
@@ -41,7 +41,7 @@
|
||||
|
||||
Radzen Blazor Components are open source and free for commercial use. You can install them from [nuget](https://www.nuget.org/packages/Radzen.Blazor) or build your own copy from source.
|
||||
|
||||
Paid support is available as part of the [Radzen Professional subscription](https://www.radzen.com/pricing/).
|
||||
Paid support is available as part of the [Radzen Professional subscription](https://www.radzen.com/blazor-studio/pricing/).
|
||||
|
||||
### :computer: Native
|
||||
|
||||
@@ -64,10 +64,10 @@ Everybody is welcome to visit the [Radzen Community forum](https://forum.radzen.
|
||||
|
||||
The Radzen team monitors the forum threads, but does not guarantee a response to every question. For guaranteed responses you may consider the dedicated support option.
|
||||
|
||||
Dedicated support for the Radzen Blazor Components is available as part of the [Radzen Professional subscription](https://www.radzen.com/pricing/).
|
||||
Dedicated support for the Radzen Blazor Components is available as part of the [Radzen Professional subscription](https://www.radzen.com/blazor-studio/pricing/).
|
||||
|
||||
Our flagship product [Radzen Studio](https://www.radzen.com/features/) provides tons of productivity features for Blazor developers:
|
||||
- The first in the industry WYSIWYG Blazor design time canvas
|
||||
Our flagship product [Radzen Blazor Studio](https://www.radzen.com/blazor-studio/) provides tons of productivity features for Blazor developers:
|
||||
- An industry-leading WYSIWYG Blazor design time canvas
|
||||
- Scaffolding a complete CRUD applications from a database
|
||||
- Built-in security - authentication and authorization
|
||||
- Visual Studio Code and Professional support
|
||||
@@ -93,7 +93,7 @@ Radzen Blazor components come with five free themes: Material, Standard, Default
|
||||
|
||||
To use a theme
|
||||
1. Pick a theme. The [online demos](https://blazor.radzen.com/colors) allow you to preview the available options via the theme dropdown located in the header. The Material theme is currently selected by default.
|
||||
1. Include the theme CSS file in your Blazor application. Open `Pages\_Layout.cshtml` (Blazor Server .NET 6+), `Pages\_Host.cshtml` (Blazor Server before .NET 6) or `wwwroot/index.html` (Blazor WebAssembly) and include the CSS file of a theme CSS file by adding this snippet
|
||||
1. Include the theme CSS file in your Blazor application. Open `Pages\_Layout.cshtml` (Blazor Server .NET 6), `Pages\_Host.cshtml` (Blazor Server .NET 7) or `wwwroot/index.html` (Blazor WebAssembly) and include a theme CSS file by adding this snippet
|
||||
```html
|
||||
<link rel="stylesheet" href="_content/Radzen.Blazor/css/material-base.css">
|
||||
```
|
||||
@@ -105,7 +105,7 @@ To include a different theme (i.e. Standard) just change the name of the CSS fil
|
||||
|
||||
### 4. Include Radzen.Blazor.js
|
||||
|
||||
Open `Pages\_Layout.cshtml` (Blazor Server .NET 6+), `Pages\_Host.cshtml` (Blazor Server before .NET 6) or `wwwroot/index.html` (Blazor WebAssembly) and include this snippet:
|
||||
Open `Pages\_Layout.cshtml` (Blazor Server .NET 6), `Pages\_Host.cshtml` (Blazor Server .NET 7) or `wwwroot/index.html` (Blazor WebAssembly) and include this snippet:
|
||||
|
||||
```html
|
||||
<script src="_content/Radzen.Blazor/Radzen.Blazor.js"></script>
|
||||
@@ -137,3 +137,6 @@ Use any Radzen Blazor component by typing its tag name in a Blazor page e.g.
|
||||
}
|
||||
}
|
||||
```
|
||||
## Run demos locally
|
||||
|
||||
Use Radzen.Server.sln to open and run demos as Blazor server application or Radzen.WebAssembly.sln to open and run demos as Blazor WebAssembly application. Radzen.sln has reference to all projects including tests.
|
||||
44
Radzen.Blazor.Tests/ChartTests.cs
Normal file
44
Radzen.Blazor.Tests/ChartTests.cs
Normal file
@@ -0,0 +1,44 @@
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Bunit;
|
||||
using Radzen.Blazor.Rendering;
|
||||
using Xunit;
|
||||
|
||||
namespace Radzen.Blazor.Tests;
|
||||
|
||||
public class ChartTests
|
||||
{
|
||||
[Fact(Timeout = 30000)]
|
||||
public async Task Chart_Tooltip_Performance()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
|
||||
ctx.JSInterop.Setup<Rect>("Radzen.createChart", _ => true).SetResult(new Rect {Left = 0, Top = 0, Width = 200, Height = 200});
|
||||
|
||||
var seriesData = Enumerable.Range(0, 5000).Select(i => new Point { X = i, Y = i });
|
||||
var chart = ctx.RenderComponent<RadzenChart>(chartParameters =>
|
||||
chartParameters
|
||||
.AddChildContent<RadzenLineSeries<Point>>(seriesParameters =>
|
||||
seriesParameters
|
||||
.Add(p => p.CategoryProperty, nameof(Point.X))
|
||||
.Add(p => p.ValueProperty, nameof(Point.Y))
|
||||
.Add(p => p.Data, seriesData))
|
||||
.AddChildContent<RadzenCategoryAxis>(axisParameters =>
|
||||
axisParameters
|
||||
.Add(p => p.Step, 100)
|
||||
.Add(p => p.Formatter, x =>
|
||||
{
|
||||
Thread.Sleep(100);
|
||||
return $"{x}";
|
||||
})));
|
||||
|
||||
foreach (var _ in Enumerable.Range(0, 10))
|
||||
{
|
||||
await chart.InvokeAsync(() => chart.Instance.MouseMove(100, 100));
|
||||
Assert.Contains("<div class=\"rz-chart-tooltip", chart.Markup);
|
||||
await chart.InvokeAsync(() => chart.Instance.MouseMove(0, 0));
|
||||
Assert.DoesNotContain("<div class=\"rz-chart-tooltip", chart.Markup);
|
||||
}
|
||||
}
|
||||
}
|
||||
16
Radzen.Blazor.Tests/ColorPickerTests.cs
Normal file
16
Radzen.Blazor.Tests/ColorPickerTests.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
using Bunit;
|
||||
using Xunit;
|
||||
|
||||
namespace Radzen.Blazor.Tests
|
||||
{
|
||||
public class ColorPickerTests
|
||||
{
|
||||
[Fact]
|
||||
public void ColorPicker_ShouldAcceptInvalidValues()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
|
||||
var component = ctx.RenderComponent<RadzenColorPicker>(ComponentParameter.CreateParameter("Value", "invalid"));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -74,11 +74,11 @@ namespace Radzen.Blazor.Tests
|
||||
});
|
||||
});
|
||||
|
||||
var markup = new Regex(@"\s\s+").Replace(component.Markup, "").Trim();
|
||||
var data = component.FindAll(".rz-cell-data");
|
||||
|
||||
Assert.Contains(@$"<span class=""rz-cell-data"">1</span>", markup);
|
||||
Assert.Contains(@$"<span class=""rz-cell-data"">2</span>", markup);
|
||||
Assert.Contains(@$"<span class=""rz-cell-data"">3</span>", markup);
|
||||
Assert.Equal("1", data[0].TextContent.Trim());
|
||||
Assert.Equal("2", data[1].TextContent.Trim());
|
||||
Assert.Equal("3", data[2].TextContent.Trim());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -99,9 +99,8 @@ namespace Radzen.Blazor.Tests
|
||||
});
|
||||
});
|
||||
|
||||
var markup = new Regex(@"\s\s+").Replace(component.Markup, "").Trim();
|
||||
|
||||
Assert.Contains(@$"<span class=""rz-column-title"">MyId</span>", markup);
|
||||
var title = component.Find(".rz-column-title");
|
||||
Assert.Equal("MyId", title.TextContent.Trim());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
||||
@@ -49,7 +49,7 @@ namespace Radzen.Blazor.Tests
|
||||
|
||||
var component = ctx.RenderComponent<RadzenDatePicker<DateTime>>();
|
||||
|
||||
component.SetParametersAndRender(parameters => {
|
||||
component.SetParametersAndRender(parameters => {
|
||||
parameters.Add<bool>(p => p.ShowTime, true);
|
||||
parameters.Add<bool>(p => p.ShowSeconds, true);
|
||||
});
|
||||
@@ -93,7 +93,7 @@ namespace Radzen.Blazor.Tests
|
||||
|
||||
component.SetParametersAndRender(parameters => {
|
||||
parameters.Add(p => p.DateFormat, format);
|
||||
parameters.Add<object>(p => p.Value, DateTime.Now);
|
||||
parameters.Add<object>(p => p.Value, DateTime.Now);
|
||||
});
|
||||
|
||||
Assert.Contains(@$"value=""{string.Format("{0:" + format + "}", DateTime.Now)}""", component.Markup);
|
||||
@@ -146,7 +146,7 @@ namespace Radzen.Blazor.Tests
|
||||
|
||||
component.SetParametersAndRender(parameters => {
|
||||
parameters.Add<object>(p => p.Value, DateTime.Now);
|
||||
parameters.Add<bool>(p => p.AllowClear, true);
|
||||
parameters.Add<bool>(p => p.AllowClear, true);
|
||||
});
|
||||
|
||||
Assert.Contains(@$"<i class=""rz-dropdown-clear-icon rzi rzi-times""", component.Markup);
|
||||
@@ -320,12 +320,12 @@ namespace Radzen.Blazor.Tests
|
||||
DateTime previousDay = DateTime.Today.AddDays(-1);
|
||||
|
||||
using var ctx = new TestContext();
|
||||
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
|
||||
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
|
||||
|
||||
var component = ctx.RenderComponent<RadzenDatePicker<DateTime>>();
|
||||
|
||||
|
||||
var raised = false;
|
||||
object newValue = null;
|
||||
object newValue = null;
|
||||
|
||||
component.SetParametersAndRender(parameters => {
|
||||
parameters.Add(p => p.ValueChanged, args => { raised = true; newValue = args; })
|
||||
@@ -378,14 +378,14 @@ namespace Radzen.Blazor.Tests
|
||||
Assert.True(raised);
|
||||
Assert.Null(newValue);
|
||||
}
|
||||
|
||||
|
||||
[Fact]
|
||||
public void DatePicker_Respects_DateTimeMaxValue()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
|
||||
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
|
||||
|
||||
|
||||
var component = ctx.RenderComponent<RadzenDatePicker<DateTime>>(parameters =>
|
||||
{
|
||||
parameters.Add(p => p.Value, DateTime.MaxValue);
|
||||
|
||||
144
Radzen.Blazor.Tests/DropDownTests.cs
Normal file
144
Radzen.Blazor.Tests/DropDownTests.cs
Normal file
@@ -0,0 +1,144 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Bunit;
|
||||
using Xunit;
|
||||
|
||||
namespace Radzen.Blazor.Tests
|
||||
{
|
||||
public class DropDownTests
|
||||
{
|
||||
class DataItem
|
||||
{
|
||||
public string Text { get; set; }
|
||||
public int Id { get; set; }
|
||||
}
|
||||
|
||||
private static IRenderedComponent<RadzenDropDown<T>> DropDown<T>(TestContext ctx, Action<ComponentParameterCollectionBuilder<RadzenDropDown<T>>> configure = null)
|
||||
{
|
||||
var data = new [] {
|
||||
new DataItem { Text = "Item 1", Id = 1 },
|
||||
new DataItem { Text = "Item 2", Id = 2 },
|
||||
};
|
||||
|
||||
var component = ctx.RenderComponent<RadzenDropDown<T>>();
|
||||
|
||||
component.SetParametersAndRender(parameters => {
|
||||
parameters.Add(p => p.Data, data);
|
||||
parameters.Add(p => p.TextProperty, nameof(DataItem.Text));
|
||||
|
||||
if (configure != null)
|
||||
{
|
||||
configure.Invoke(parameters);
|
||||
}
|
||||
else
|
||||
{
|
||||
parameters.Add(p => p.ValueProperty, nameof(DataItem.Id));
|
||||
}
|
||||
});
|
||||
|
||||
return component;
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Dropdown_SelectItem_Method_Should_Not_Throw()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
|
||||
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
|
||||
|
||||
var component = DropDown<int>(ctx);
|
||||
|
||||
var items = component.FindAll(".rz-dropdown-item");
|
||||
|
||||
Assert.Equal(2, items.Count);
|
||||
|
||||
//this throws
|
||||
await component.InvokeAsync(async () => await component.Instance.SelectItem(1));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DropDown_RendersItems()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
|
||||
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
|
||||
|
||||
var component = DropDown<int>(ctx);
|
||||
|
||||
var items = component.FindAll(".rz-dropdown-item");
|
||||
|
||||
Assert.Equal(2, items.Count);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DropDown_AppliesSelectionStyleForIntValue()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
|
||||
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
|
||||
|
||||
var component = DropDown<int>(ctx);
|
||||
|
||||
var items = component.FindAll(".rz-dropdown-item");
|
||||
|
||||
items[0].Click();
|
||||
|
||||
component.Render();
|
||||
|
||||
items = component.FindAll(".rz-dropdown-item");
|
||||
|
||||
Assert.Contains("rz-state-highlight", items[0].ClassList);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DropDown_AppliesSelectionStyleForStringValue()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
|
||||
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
|
||||
|
||||
var component = DropDown<string>(ctx, parameters => {
|
||||
parameters.Add(p => p.ValueProperty, nameof(DataItem.Text));
|
||||
});
|
||||
|
||||
var items = component.FindAll(".rz-dropdown-item");
|
||||
|
||||
items[0].Click();
|
||||
|
||||
component.Render();
|
||||
|
||||
items = component.FindAll(".rz-dropdown-item");
|
||||
|
||||
Assert.Contains("rz-state-highlight", items[0].ClassList);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DropDown_AppliesSelectionStyleWhenMultipleSelectionIsEnabled()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
|
||||
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
|
||||
|
||||
var component = DropDown<string>(ctx, parameters => {
|
||||
parameters.Add(p => p.ValueProperty, nameof(DataItem.Text));
|
||||
parameters.Add(p => p.Multiple, true);
|
||||
});
|
||||
|
||||
var items = component.FindAll(".rz-multiselect-item");
|
||||
|
||||
items[0].Click();
|
||||
|
||||
component.Render();
|
||||
|
||||
items = component.FindAll(".rz-multiselect-item");
|
||||
|
||||
items[1].Click();
|
||||
|
||||
component.Render();
|
||||
|
||||
var selectedItems = component.FindAll(".rz-state-highlight");
|
||||
|
||||
Assert.Equal(2, selectedItems.Count);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -30,8 +30,10 @@ namespace Radzen.Blazor.Tests
|
||||
|
||||
component.SetParametersAndRender(parameters => parameters.Add(p => p.Text, text));
|
||||
|
||||
Assert.Contains(@$">{text}</span>", component.Markup);
|
||||
Assert.Contains(@$"class=""rz-link-text""", component.Markup);
|
||||
var textElement = component.Find(".rz-link-text");
|
||||
|
||||
Assert.NotNull(textElement);
|
||||
Assert.Equal(text, textElement.TextContent.Trim());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
||||
@@ -26,7 +26,12 @@ namespace Radzen.Blazor.Tests
|
||||
|
||||
var component = ctx.RenderComponent<RadzenLogin>();
|
||||
|
||||
Assert.Contains(@$"<label class=""rz-label"" for=""username"">Username</label>", component.Markup);
|
||||
component.SetParametersAndRender(p => {
|
||||
p.AddUnmatched("id", "login");
|
||||
});
|
||||
|
||||
var label = component.Find($@"label[for=""login-username""]");
|
||||
Assert.NotNull(label);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -63,7 +68,7 @@ namespace Radzen.Blazor.Tests
|
||||
component.SetParametersAndRender(parameters => {
|
||||
parameters.Add(p => p.Username, "user");
|
||||
parameters.Add(p => p.Password, "pwd");
|
||||
parameters.Add(p => p.Login, args => { clicked = true; });
|
||||
parameters.Add(p => p.Login, args => { clicked = true; });
|
||||
});
|
||||
|
||||
component.Find("button").Click();
|
||||
|
||||
139
Radzen.Blazor.Tests/NumericRangeValidatorTests.cs
Normal file
139
Radzen.Blazor.Tests/NumericRangeValidatorTests.cs
Normal file
@@ -0,0 +1,139 @@
|
||||
using System;
|
||||
using Bunit;
|
||||
using Microsoft.AspNetCore.Components.Forms;
|
||||
using Xunit;
|
||||
|
||||
namespace Radzen.Blazor.Tests
|
||||
{
|
||||
public class NumericRangeValidatorTests
|
||||
{
|
||||
class FormComponentTestDouble : IRadzenFormComponent
|
||||
{
|
||||
public bool IsBound => false;
|
||||
|
||||
public bool HasValue => true;
|
||||
|
||||
public string Name { get; set; }
|
||||
|
||||
public FieldIdentifier FieldIdentifier => throw new System.NotImplementedException();
|
||||
|
||||
public object GetValue()
|
||||
{
|
||||
return Value;
|
||||
}
|
||||
|
||||
public object Value { get; set; }
|
||||
}
|
||||
|
||||
class RadzenNumericRangeValidatorTestDouble : RadzenNumericRangeValidator
|
||||
{
|
||||
public bool Validate(object value)
|
||||
{
|
||||
return base.Validate(new FormComponentTestDouble { Value = value });
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Throws_Exception_If_Min_And_Max_Are_Null()
|
||||
{
|
||||
var validator = new RadzenNumericRangeValidatorTestDouble();
|
||||
|
||||
Assert.Throws<System.ArgumentException>(() => validator.Validate(1));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Returns_False_If_Value_Is_Null()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
var component = ctx.RenderComponent<RadzenNumericRangeValidatorTestDouble>();
|
||||
|
||||
component.SetParametersAndRender(parameters =>
|
||||
{
|
||||
component.SetParametersAndRender(parameters => parameters.Add(p => p.Min, 0).Add(p => p.Max, 10));
|
||||
});
|
||||
|
||||
Assert.False(component.Instance.Validate(null));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Returns_True_If_Value_Is_Greater_Than_Min()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
var component = ctx.RenderComponent<RadzenNumericRangeValidatorTestDouble>();
|
||||
component.SetParametersAndRender(parameters => parameters.Add(p => p.Min, 0));
|
||||
|
||||
Assert.True(component.Instance.Validate(1));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Returns_True_If_Value_Is_Equal_To_Min()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
var component = ctx.RenderComponent<RadzenNumericRangeValidatorTestDouble>();
|
||||
component.SetParametersAndRender(parameters => parameters.Add(p => p.Min, 0));
|
||||
|
||||
Assert.True(component.Instance.Validate(0));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Returns_True_If_Value_Is_Less_Than_Max()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
var component = ctx.RenderComponent<RadzenNumericRangeValidatorTestDouble>();
|
||||
component.SetParametersAndRender(parameters => parameters.Add(p => p.Max, 10));
|
||||
|
||||
Assert.True(component.Instance.Validate(9));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Returns_True_If_Value_Is_Equal_To_Max()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
var component = ctx.RenderComponent<RadzenNumericRangeValidatorTestDouble>();
|
||||
component.SetParametersAndRender(parameters => parameters.Add(p => p.Max, 10));
|
||||
|
||||
Assert.True(component.Instance.Validate(10));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Returns_True_If_Value_Is_Between_Min_And_Max()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
var component = ctx.RenderComponent<RadzenNumericRangeValidatorTestDouble>();
|
||||
component.SetParametersAndRender(parameters => parameters.Add(p => p.Min, 0).Add(p => p.Max, 10));
|
||||
|
||||
Assert.True(component.Instance.Validate(5));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Returns_True_If_Value_Is_Between_Min_And_Max_And_They_Are_Nullable()
|
||||
{
|
||||
int? min = 0;
|
||||
int? max = 10;
|
||||
using var ctx = new TestContext();
|
||||
var component = ctx.RenderComponent<RadzenNumericRangeValidatorTestDouble>();
|
||||
component.SetParametersAndRender(parameters => parameters.Add(p => p.Min, min).Add(p => p.Max, max));
|
||||
Assert.True(component.Instance.Validate(5));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Returns_True_When_Value_Is_Of_DifferentType()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
var component = ctx.RenderComponent<RadzenNumericRangeValidatorTestDouble>();
|
||||
component.SetParametersAndRender(parameters => parameters.Add(p => p.Min, 0m).Add(p => p.Max, 10m));
|
||||
|
||||
Assert.True(component.Instance.Validate(5));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Returns_False_If_Cannot_Conert_Value()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
var component = ctx.RenderComponent<RadzenNumericRangeValidatorTestDouble>();
|
||||
component.SetParametersAndRender(parameters => parameters.Add(p => p.Min, 0m).Add(p => p.Max, 10m));
|
||||
|
||||
Assert.False(component.Instance.Validate(DateTime.Now));
|
||||
}
|
||||
}
|
||||
}
|
||||
120
Radzen.Blazor.Tests/PropertyAccessTests.cs
Normal file
120
Radzen.Blazor.Tests/PropertyAccessTests.cs
Normal file
@@ -0,0 +1,120 @@
|
||||
using AngleSharp.Css;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Linq.Dynamic.Core;
|
||||
using Xunit;
|
||||
|
||||
namespace Radzen.Blazor.Tests
|
||||
{
|
||||
public class PropertyAccessTests
|
||||
{
|
||||
public partial class TestData
|
||||
{
|
||||
public string PROPERTY { get; set; }
|
||||
public string Property { get; set; }
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Getter_With_DifferentTargetType()
|
||||
{
|
||||
var o = new TestData { Property = "test" };
|
||||
var getter = PropertyAccess.Getter<object, object>(nameof(TestData.Property), typeof(TestData));
|
||||
var value = getter(o);
|
||||
Assert.Equal(o.Property, value);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Getter_With_Members_That_Differ_Only_In_Casing()
|
||||
{
|
||||
var o = new TestData { PROPERTY = nameof(TestData.PROPERTY), Property = nameof(TestData.Property) };
|
||||
var getter = PropertyAccess.Getter<TestData, string>(nameof(TestData.PROPERTY));
|
||||
var value = getter(o);
|
||||
Assert.Equal(nameof(TestData.PROPERTY), value);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Getter_Resolves_Property_On_Simple_Object()
|
||||
{
|
||||
var o = new SimpleObject() { Prop1 = "TestString" };
|
||||
var getter = PropertyAccess.Getter<SimpleObject, string>("Prop1");
|
||||
var value = getter(o);
|
||||
Assert.Equal("TestString", value);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Getter_Resolves_Property_On_Simple_Object_QueryableType()
|
||||
{
|
||||
var _data = new List<SimpleObject>()
|
||||
{
|
||||
new SimpleObject() { Prop1 = "TestString" },
|
||||
};
|
||||
|
||||
Func<object, object> getter = PropertyAccess.Getter<object, object>("Prop1", typeof(SimpleObject));
|
||||
|
||||
var value = getter(_data[0]);
|
||||
Assert.Equal("TestString", value);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Getter_Resolves_Property_On_Nested_Object()
|
||||
{
|
||||
var o = new NestedObject() { Obj = new SimpleObject { Prop1 = "TestString" } };
|
||||
var getter = PropertyAccess.Getter<NestedObject, string>("Obj.Prop1");
|
||||
var value = getter(o);
|
||||
Assert.Equal("TestString", value);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Getter_Resolves_Property_From_Array()
|
||||
{
|
||||
var o = new ArrayObject() { Values = new string[] { "1", "2", "3" } };
|
||||
var getter = PropertyAccess.Getter<ArrayObject, string>("Values[1]");
|
||||
var value = getter(o);
|
||||
Assert.Equal("2", value);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Getter_Resolves_Property_From_Nested_Array()
|
||||
{
|
||||
var o = new NestedArrayObject() { Obj = new ArrayObject() { Values = new string[] { "1", "2", "3" } } };
|
||||
var getter = PropertyAccess.Getter<NestedArrayObject, string>("Obj.Values[2]");
|
||||
var value = getter(o);
|
||||
Assert.Equal("3", value);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Getter_Resolves_Property_From_List()
|
||||
{
|
||||
var o = new ListObject() { Values = new List<string>() { "1", "2", "3" } };
|
||||
var getter = PropertyAccess.Getter<ListObject, string>("Values[1]");
|
||||
var value = getter(o);
|
||||
Assert.Equal("2", value);
|
||||
}
|
||||
|
||||
public class SimpleObject
|
||||
{
|
||||
public string Prop1 { get; set; }
|
||||
}
|
||||
|
||||
public class NestedObject
|
||||
{
|
||||
public SimpleObject Obj { get; set; }
|
||||
}
|
||||
|
||||
public class ArrayObject
|
||||
{
|
||||
public string[] Values { get; set; }
|
||||
}
|
||||
|
||||
public class NestedArrayObject
|
||||
{
|
||||
public ArrayObject Obj { get; set; }
|
||||
}
|
||||
|
||||
public class ListObject
|
||||
{
|
||||
public List<string> Values { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
25
Radzen.Blazor.Tests/Rendering/StepGeneratorTests.cs
Normal file
25
Radzen.Blazor.Tests/Rendering/StepGeneratorTests.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
using System.Collections.Generic;
|
||||
using Radzen.Blazor.Rendering;
|
||||
using Xunit;
|
||||
|
||||
namespace Radzen.Blazor.Tests.Rendering;
|
||||
|
||||
public class StepGeneratorTests
|
||||
{
|
||||
[Fact]
|
||||
public void Renders_Path_Correctly()
|
||||
{
|
||||
var data = new List<Point>
|
||||
{
|
||||
new() { X = 10, Y = 10 },
|
||||
new() { X = 20, Y = 15 },
|
||||
new() { X = 30, Y = 20 },
|
||||
new() { X = 40, Y = 25 },
|
||||
new() { X = 50, Y = 50 }
|
||||
};
|
||||
|
||||
var path = new StepGenerator().Path(data);
|
||||
|
||||
Assert.Equal("10 10 H 20 V 15 H 30 V 20 H 40 V 25 H 50 V 50", path);
|
||||
}
|
||||
}
|
||||
197
Radzen.Blazor.Tests/SpeechToTextButtonTests.cs
Normal file
197
Radzen.Blazor.Tests/SpeechToTextButtonTests.cs
Normal file
@@ -0,0 +1,197 @@
|
||||
using Bunit;
|
||||
using Xunit;
|
||||
|
||||
namespace Radzen.Blazor.Tests
|
||||
{
|
||||
public class SpeechToTextButtonTests
|
||||
{
|
||||
[Fact]
|
||||
public void SpeechToTextButton_Renders_Record_Button_When_Visible()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
|
||||
var component = ctx.RenderComponent<RadzenSpeechToTextButton>();
|
||||
|
||||
component.Render();
|
||||
|
||||
var recordButton = component.Find("button.rz-button-icon-only.rz-speech-to-text-button");
|
||||
|
||||
Assert.NotNull(recordButton);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SpeechToTextButton_Does_Not_Renders_Record_Button_When_Visible_False()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
|
||||
var component = ctx.RenderComponent<RadzenSpeechToTextButton>();
|
||||
|
||||
component.SetParametersAndRender(parameters =>
|
||||
{
|
||||
parameters.Add(p => p.Visible, false);
|
||||
});
|
||||
|
||||
Assert.Throws<ElementNotFoundException>(() => component.Find("button.rz-button-icon-only.rz-speech-to-text-button"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SpeechToTextButton_Renders_Additional_Css()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
|
||||
var component =
|
||||
ctx.RenderComponent<RadzenSpeechToTextButton>(ComponentParameter.CreateParameter("class", "another-class"));
|
||||
|
||||
var recordButton = component.Find("button.rz-button-icon-only.rz-speech-to-text-button.another-class");
|
||||
|
||||
Assert.NotNull(recordButton);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SpeechToTextButton_Can_Override_Default_Title_And_Aria_Label()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
|
||||
var component =
|
||||
ctx.RenderComponent<RadzenSpeechToTextButton>(
|
||||
ComponentParameter.CreateParameter("title", "title override"),
|
||||
ComponentParameter.CreateParameter("aria-label", "aria-label override"));
|
||||
|
||||
var recordButton = component.Find("button.rz-button-icon-only.rz-speech-to-text-button");
|
||||
|
||||
Assert.NotNull(recordButton);
|
||||
Assert.Equal("title override", recordButton.GetAttribute("title"));
|
||||
Assert.Equal("aria-label override", recordButton.GetAttribute("aria-label"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SpeechToTextButton_Sets_Record_Button_Css_When_Record_Button_Clicked()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
|
||||
var component = ctx.RenderComponent<RadzenSpeechToTextButton>();
|
||||
|
||||
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
|
||||
|
||||
component.Render();
|
||||
|
||||
var recordButton = component.Find("button.rz-button-icon-only.rz-speech-to-text-button");
|
||||
|
||||
Assert.NotNull(recordButton);
|
||||
|
||||
recordButton.Click();
|
||||
|
||||
component.Render();
|
||||
|
||||
var blinkingRecordButton = component.Find("button.rz-button-icon-only.rz-speech-to-text-button-recording");
|
||||
|
||||
Assert.NotNull(blinkingRecordButton);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SpeechToTextButton_Sets_StopTitle_When_Record_Button_Clicked()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
|
||||
var component = ctx.RenderComponent<RadzenSpeechToTextButton>();
|
||||
|
||||
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
|
||||
|
||||
component.Render();
|
||||
|
||||
var recordButton = component.Find("button.rz-button-icon-only.rz-speech-to-text-button");
|
||||
|
||||
Assert.NotNull(recordButton);
|
||||
|
||||
recordButton.Click();
|
||||
|
||||
component.Render();
|
||||
|
||||
var blinkingRecordButton = component.Find("button.rz-button-icon-only.rz-speech-to-text-button-recording");
|
||||
|
||||
Assert.Equal(component.Instance.StopTitle, blinkingRecordButton.GetAttribute("title"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SpeechToTextButton_ChangesIconWhen_When_Record_Button_Clicked()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
|
||||
var component = ctx.RenderComponent<RadzenSpeechToTextButton>();
|
||||
|
||||
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
|
||||
|
||||
component.Render();
|
||||
|
||||
var recordButton = component.Find("button.rz-button-icon-only.rz-speech-to-text-button");
|
||||
|
||||
Assert.NotNull(recordButton);
|
||||
|
||||
recordButton.Click();
|
||||
|
||||
component.Render();
|
||||
|
||||
var blinkingRecordButton = component.Find("button span");
|
||||
|
||||
Assert.Contains("stop", blinkingRecordButton.TextContent);
|
||||
Assert.DoesNotContain("mic", blinkingRecordButton.TextContent);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SpeechToTextButton_UnSets_Record_Button_Css_When_Record_Button_Clicked_Twice()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
|
||||
var component = ctx.RenderComponent<RadzenSpeechToTextButton>();
|
||||
|
||||
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
|
||||
|
||||
component.Render();
|
||||
|
||||
var recordButton = component.Find("button.rz-button-icon-only.rz-speech-to-text-button");
|
||||
|
||||
Assert.NotNull(recordButton);
|
||||
|
||||
recordButton.Click();
|
||||
|
||||
component.Render();
|
||||
|
||||
const string blinkingRecordButtonSelector = "button.rz-button-icon-only.rz-speech-to-text-button-recording";
|
||||
var blinkingRecordButton = component.Find(blinkingRecordButtonSelector);
|
||||
|
||||
Assert.NotNull(blinkingRecordButton);
|
||||
|
||||
blinkingRecordButton.Click();
|
||||
|
||||
component.Render();
|
||||
|
||||
Assert.Throws<ElementNotFoundException>(() => component.Find(blinkingRecordButtonSelector));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SpeechToTextButton_Invokes_OnResult_FromJs()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
|
||||
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
|
||||
|
||||
var component = ctx.RenderComponent<RadzenSpeechToTextButton>();
|
||||
|
||||
string resultsFromJs = null;
|
||||
|
||||
component.SetParametersAndRender(parameters => parameters.Add(p => p.Change, r => resultsFromJs = r));
|
||||
|
||||
var recordButton = component.Find("button.rz-button-icon-only.rz-speech-to-text-button");
|
||||
|
||||
Assert.NotNull(recordButton);
|
||||
|
||||
recordButton.Click();
|
||||
|
||||
const string speechResults = "results from js";
|
||||
|
||||
component.InvokeAsync(() => component.Instance.OnResult(speechResults));
|
||||
|
||||
Assert.Equal(speechResults, resultsFromJs);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -467,7 +467,7 @@ namespace Radzen.Blazor
|
||||
builder.AddAttribute(1, nameof(ChartTooltip.X), x + marginLeft);
|
||||
builder.AddAttribute(2, nameof(ChartTooltip.Y), y + marginTop);
|
||||
|
||||
builder.AddAttribute(3, nameof(ChartTooltip.ChildContent), TooltipTemplate == null ? null : TooltipTemplate(item));
|
||||
builder.AddAttribute(3, nameof(ChartTooltip.ChildContent), TooltipTemplate?.Invoke(item));
|
||||
|
||||
builder.AddAttribute(4, nameof(ChartTooltip.Title), TooltipTitle(item));
|
||||
builder.AddAttribute(5, nameof(ChartTooltip.Label), TooltipLabel(item));
|
||||
|
||||
@@ -7,7 +7,10 @@ using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Linq.Dynamic.Core;
|
||||
using System.Linq.Dynamic.Core.Parser;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Text.Encodings.Web;
|
||||
using System.Text.Json;
|
||||
using System.Threading.Tasks;
|
||||
@@ -78,6 +81,11 @@ namespace Radzen
|
||||
/// SecondFilterOperator.
|
||||
/// </summary>
|
||||
public FilterOperator SecondFilterOperator { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// LogicalFilterOperator.
|
||||
/// </summary>
|
||||
public LogicalFilterOperator LogicalFilterOperator { get; set; }
|
||||
}
|
||||
#if NET7_0_OR_GREATER
|
||||
#else
|
||||
@@ -666,6 +674,33 @@ namespace Radzen
|
||||
Multiple
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Specifies the grid lines of <see cref="RadzenDataGrid{TItem}" />.
|
||||
/// </summary>
|
||||
public enum DataGridGridLines
|
||||
{
|
||||
/// <summary>
|
||||
/// Theme default.
|
||||
/// </summary>
|
||||
Default,
|
||||
/// <summary>
|
||||
/// Both horizontal and vertical grid lines.
|
||||
/// </summary>
|
||||
Both,
|
||||
/// <summary>
|
||||
/// No grid lines.
|
||||
/// </summary>
|
||||
None,
|
||||
/// <summary>
|
||||
/// Horizontal grid lines.
|
||||
/// </summary>
|
||||
Horizontal,
|
||||
/// <summary>
|
||||
/// Vertical grid lines.
|
||||
/// </summary>
|
||||
Vertical
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Specifies the severity of a <see cref="RadzenNotification" />. Severity changes the visual styling of the RadzenNotification (icon and background color).
|
||||
/// </summary>
|
||||
@@ -824,6 +859,99 @@ namespace Radzen
|
||||
Vertical
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents whether items are forced onto one line or can wrap onto multiple lines.
|
||||
/// </summary>
|
||||
public enum FlexWrap
|
||||
{
|
||||
/// <summary>
|
||||
/// The items are laid out in a single line.
|
||||
/// </summary>
|
||||
NoWrap,
|
||||
/// <summary>
|
||||
/// The items break into multiple lines.
|
||||
/// </summary>
|
||||
Wrap,
|
||||
/// <summary>
|
||||
/// The items break into multiple lines reversed.
|
||||
/// </summary>
|
||||
WrapReverse
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents content justification of Stack items.
|
||||
/// </summary>
|
||||
public enum JustifyContent
|
||||
{
|
||||
/// <summary>
|
||||
/// Normal content justification of Stack items.
|
||||
/// </summary>
|
||||
Normal,
|
||||
/// <summary>
|
||||
/// Center content justification of Stack items.
|
||||
/// </summary>
|
||||
Center,
|
||||
/// <summary>
|
||||
/// Start content justification of Stack items.
|
||||
/// </summary>
|
||||
Start,
|
||||
/// <summary>
|
||||
/// End content justification of Stack items.
|
||||
/// </summary>
|
||||
End,
|
||||
/// <summary>
|
||||
/// Left content justification of Stack items.
|
||||
/// </summary>
|
||||
Left,
|
||||
/// <summary>
|
||||
/// Right content justification of Stack items.
|
||||
/// </summary>
|
||||
Right,
|
||||
/// <summary>
|
||||
/// SpaceBetween content justification of Stack items.
|
||||
/// </summary>
|
||||
SpaceBetween,
|
||||
/// <summary>
|
||||
/// SpaceAround content justification of Stack items.
|
||||
/// </summary>
|
||||
SpaceAround,
|
||||
/// <summary>
|
||||
/// SpaceEvenly content justification of Stack items.
|
||||
/// </summary>
|
||||
SpaceEvenly,
|
||||
/// <summary>
|
||||
/// Stretch content justification of Stack items.
|
||||
/// </summary>
|
||||
Stretch
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents the alignment of Stack items.
|
||||
/// </summary>
|
||||
public enum AlignItems
|
||||
{
|
||||
/// <summary>
|
||||
/// Normal items alignment.
|
||||
/// </summary>
|
||||
Normal,
|
||||
/// <summary>
|
||||
/// Center items alignment.
|
||||
/// </summary>
|
||||
Center,
|
||||
/// <summary>
|
||||
/// Start items alignment.
|
||||
/// </summary>
|
||||
Start,
|
||||
/// <summary>
|
||||
/// End items alignment.
|
||||
/// </summary>
|
||||
End,
|
||||
/// <summary>
|
||||
/// Stretch items alignment.
|
||||
/// </summary>
|
||||
Stretch
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Specifies the sort order in components that support sorting.
|
||||
/// </summary>
|
||||
@@ -1940,28 +2068,61 @@ namespace Radzen
|
||||
/// <returns>A function which return the specified property by its name.</returns>
|
||||
public static Func<TItem, TValue> Getter<TItem, TValue>(string propertyName, Type type = null)
|
||||
{
|
||||
var arg = Expression.Parameter(typeof(TItem));
|
||||
|
||||
Expression body = arg;
|
||||
|
||||
if (type != null)
|
||||
if (propertyName.Contains("["))
|
||||
{
|
||||
body = Expression.Convert(body, type);
|
||||
return DynamicExpressionParser.ParseLambda<TItem, TValue>(null, false, propertyName).Compile();
|
||||
}
|
||||
|
||||
foreach (var member in propertyName.Split("."))
|
||||
else
|
||||
{
|
||||
body = !body.Type.IsInterface ?
|
||||
Expression.PropertyOrField(body, member) :
|
||||
Expression.Property(
|
||||
body,
|
||||
new Type[] { body.Type }.Concat(body.Type.GetInterfaces()).FirstOrDefault(t => t.GetProperty(member) != null),
|
||||
member);
|
||||
var arg = Expression.Parameter(typeof(TItem));
|
||||
|
||||
Expression body = arg;
|
||||
|
||||
if (type != null)
|
||||
{
|
||||
body = Expression.Convert(body, type);
|
||||
}
|
||||
|
||||
foreach (var member in propertyName.Split("."))
|
||||
{
|
||||
if (body.Type.IsInterface)
|
||||
{
|
||||
body = Expression.Property(body,
|
||||
new [] { body.Type }.Concat(body.Type.GetInterfaces()).FirstOrDefault(t => t.GetProperty(member) != null),
|
||||
member
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
body = Expression.PropertyOrField(body, member);
|
||||
}
|
||||
catch (AmbiguousMatchException)
|
||||
{
|
||||
var property = body.Type.GetProperty(member, BindingFlags.Instance | BindingFlags.Public | BindingFlags.FlattenHierarchy);
|
||||
|
||||
if (property != null)
|
||||
{
|
||||
body = Expression.Property(body, property);
|
||||
}
|
||||
else
|
||||
{
|
||||
var field = body.Type.GetField(member, BindingFlags.Instance | BindingFlags.Public | BindingFlags.FlattenHierarchy);
|
||||
|
||||
if (field != null)
|
||||
{
|
||||
body = Expression.Field(body, field);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
body = Expression.Convert(body, typeof(TValue));
|
||||
|
||||
return Expression.Lambda<Func<TItem, TValue>>(body, arg).Compile();
|
||||
}
|
||||
|
||||
body = Expression.Convert(body, typeof(TValue));
|
||||
|
||||
return Expression.Lambda<Func<TItem, TValue>>(body, arg).Compile();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -2326,6 +2487,52 @@ namespace Radzen
|
||||
public RenderFragment ChildContent { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A base class of row/col components.
|
||||
/// </summary>
|
||||
public class RadzenFlexComponent : RadzenComponentWithChildren
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the content justify.
|
||||
/// </summary>
|
||||
/// <value>The content justify.</value>
|
||||
[Parameter]
|
||||
public JustifyContent JustifyContent { get; set; } = JustifyContent.Normal;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the items alignment.
|
||||
/// </summary>
|
||||
/// <value>The items alignment.</value>
|
||||
[Parameter]
|
||||
public AlignItems AlignItems { get; set; } = AlignItems.Normal;
|
||||
|
||||
internal string GetFlexCSSClass<T>(Enum v)
|
||||
{
|
||||
var value = ToDashCase(Enum.GetName(typeof(T), v));
|
||||
return value == "start" || value == "end" ? $"flex-{value}" : value;
|
||||
}
|
||||
|
||||
internal string ToDashCase(string value)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
|
||||
foreach (var ch in value)
|
||||
{
|
||||
if ((char.IsUpper(ch) && sb.Length > 0) || char.IsSeparator(ch))
|
||||
{
|
||||
sb.Append('-');
|
||||
}
|
||||
|
||||
if (char.IsLetterOrDigit(ch))
|
||||
{
|
||||
sb.Append(char.ToLowerInvariant(ch));
|
||||
}
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
class Debouncer
|
||||
{
|
||||
System.Timers.Timer timer;
|
||||
|
||||
@@ -80,6 +80,11 @@ namespace Radzen
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
if (_sideDialogTask?.Task.IsCompleted == false)
|
||||
{
|
||||
CloseSide();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -97,6 +102,16 @@ namespace Radzen
|
||||
/// </summary>
|
||||
public event Action<string, Type, Dictionary<string, object>, DialogOptions> OnOpen;
|
||||
|
||||
/// <summary>
|
||||
/// Raises the Close event for the side dialog
|
||||
/// </summary>
|
||||
public event Action<dynamic> OnSideClose;
|
||||
|
||||
/// <summary>
|
||||
/// Raises the Open event for the side dialog
|
||||
/// </summary>
|
||||
public event Action<Type, Dictionary<string, object>, SideDialogOptions> OnSideOpen;
|
||||
|
||||
/// <summary>
|
||||
/// Opens a dialog with the specified arguments.
|
||||
/// </summary>
|
||||
@@ -121,6 +136,7 @@ namespace Radzen
|
||||
/// The tasks
|
||||
/// </summary>
|
||||
protected List<TaskCompletionSource<dynamic>> tasks = new List<TaskCompletionSource<dynamic>>();
|
||||
private TaskCompletionSource<dynamic> _sideDialogTask;
|
||||
|
||||
/// <summary>
|
||||
/// Opens a dialog with the specified arguments.
|
||||
@@ -140,6 +156,42 @@ namespace Radzen
|
||||
return task.Task;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Opens a side dialog with the specified arguments
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of Blazor component which will be displayed in the side dialog.</typeparam>
|
||||
/// <param name="title">The text displayed in the title bar of the side dialog.</param>
|
||||
/// <param name="parameters">The dialog parameters. Passed as property values of <typeparamref name="T"/></param>
|
||||
/// <param name="options">The side dialog options.</param>
|
||||
/// <returns>A task that completes when the dialog is closed or a new one opened</returns>
|
||||
public Task<dynamic> OpenSideAsync<T>(string title, Dictionary<string, object> parameters = null, SideDialogOptions options = null)
|
||||
where T : ComponentBase
|
||||
{
|
||||
CloseSide();
|
||||
_sideDialogTask = new TaskCompletionSource<dynamic>();
|
||||
if (options == null)
|
||||
{
|
||||
options = new SideDialogOptions();
|
||||
}
|
||||
|
||||
options.Title = title;
|
||||
OnSideOpen?.Invoke(typeof(T), parameters ?? new Dictionary<string, object>(), options);
|
||||
return _sideDialogTask.Task;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Closes the side dialog
|
||||
/// </summary>
|
||||
/// <param name="result">The result of the Dialog</param>
|
||||
public void CloseSide(dynamic result = null)
|
||||
{
|
||||
if (_sideDialogTask?.Task.IsCompleted == false)
|
||||
{
|
||||
_sideDialogTask.TrySetResult(result);
|
||||
OnSideClose?.Invoke(result);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Opens a dialog with the specified content.
|
||||
/// </summary>
|
||||
@@ -264,8 +316,6 @@ namespace Radzen
|
||||
CssClass = options != null ? $"rz-dialog-confirm {options.CssClass}" : "rz-dialog-confirm",
|
||||
};
|
||||
|
||||
await JSRuntime.InvokeAsync<string>("Radzen.openDialog", dialogOptions, Reference);
|
||||
|
||||
return await OpenAsync(title, ds =>
|
||||
{
|
||||
RenderFragment content = b =>
|
||||
@@ -324,8 +374,6 @@ namespace Radzen
|
||||
CssClass = options != null ? $"rz-dialog-alert {options.CssClass}" : "rz-dialog-alert",
|
||||
};
|
||||
|
||||
await JSRuntime.InvokeAsync<string>("Radzen.openDialog", dialogOptions, Reference);
|
||||
|
||||
return await OpenAsync(title, ds =>
|
||||
{
|
||||
RenderFragment content = b =>
|
||||
@@ -352,9 +400,9 @@ namespace Radzen
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Class DialogOptions.
|
||||
/// Base Class for dialog options
|
||||
/// </summary>
|
||||
public class DialogOptions
|
||||
public abstract class DialogOptionsBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether to show the title bar. Set to <c>true</c> by default.
|
||||
@@ -367,7 +415,83 @@ namespace Radzen
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if the close button is shown; otherwise, <c>false</c>.</value>
|
||||
public bool ShowClose { get; set; } = true;
|
||||
/// <summary>
|
||||
/// Gets or sets the width of the dialog.
|
||||
/// </summary>
|
||||
/// <value>The width.</value>
|
||||
public string Width { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the height of the dialog.
|
||||
/// </summary>
|
||||
/// <value>The height.</value>
|
||||
public string Height { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the CSS style of the dialog
|
||||
/// </summary>
|
||||
/// <value>The style.</value>
|
||||
public string Style { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether the dialog should be closed by clicking the overlay.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if closeable; otherwise, <c>false</c>.</value>
|
||||
public bool CloseDialogOnOverlayClick { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets dialog box custom class
|
||||
/// </summary>
|
||||
public string CssClass { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Class SideDialogOptions
|
||||
/// </summary>
|
||||
public class SideDialogOptions : DialogOptionsBase
|
||||
{
|
||||
/// <summary>
|
||||
/// The title displayed on the dialog.
|
||||
/// </summary>
|
||||
public string Title { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The Position on which the dialog will be positioned
|
||||
/// </summary>
|
||||
public DialogPosition Position { get; set; } = DialogPosition.Right;
|
||||
|
||||
/// <summary>
|
||||
/// Whether to show a mask on the background or not
|
||||
/// </summary>
|
||||
public bool ShowMask { get; set; } = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// DialogPosition enum
|
||||
/// </summary>
|
||||
public enum DialogPosition
|
||||
{
|
||||
/// <summary>
|
||||
/// Dialog will be positioned on the right side
|
||||
/// </summary>
|
||||
Right,
|
||||
/// <summary>
|
||||
/// Dialog will be positioned on the left side
|
||||
/// </summary>
|
||||
Left,
|
||||
/// <summary>
|
||||
/// Dialog will be positioned on the top of the page
|
||||
/// </summary>
|
||||
Top,
|
||||
/// <summary>
|
||||
/// Dialog will be positioned at the bottom of the page
|
||||
/// </summary>
|
||||
Bottom
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Class DialogOptions.
|
||||
/// </summary>
|
||||
public class DialogOptions : DialogOptionsBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether the dialog is resizable. Set to <c>false</c> by default.
|
||||
/// </summary>
|
||||
@@ -394,21 +518,6 @@ namespace Radzen
|
||||
/// <value>The bottom.</value>
|
||||
public string Bottom { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the width of the dialog.
|
||||
/// </summary>
|
||||
/// <value>The width.</value>
|
||||
public string Width { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the height of the dialog.
|
||||
/// </summary>
|
||||
/// <value>The height.</value>
|
||||
public string Height { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the CSS style of the dialog
|
||||
/// </summary>
|
||||
/// <value>The style.</value>
|
||||
public string Style { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the child content.
|
||||
/// </summary>
|
||||
/// <value>The child content.</value>
|
||||
@@ -417,23 +526,11 @@ namespace Radzen
|
||||
/// Gets or sets a value indicating whether to focus the first focusable HTML element. Set to <c>true</c> by default.
|
||||
/// </summary>
|
||||
public bool AutoFocusFirstElement { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether the dialog should be closed by clicking the overlay.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if closeable; otherwise, <c>false</c>.</value>
|
||||
public bool CloseDialogOnOverlayClick { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether the dialog should be closed on ESC key press.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if closeable; otherwise, <c>false</c>.</value>
|
||||
public bool CloseDialogOnEsc { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets dialog box custom class
|
||||
/// </summary>
|
||||
public string CssClass { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -248,10 +248,10 @@ namespace Radzen
|
||||
return;
|
||||
}
|
||||
|
||||
if (selectedItems.Count != View.Cast<object>().Count())
|
||||
if (selectedItems.Count != View.Cast<object>().ToList().Where(i => disabledPropertyGetter != null ? disabledPropertyGetter(i) as bool? != true : true).Count())
|
||||
{
|
||||
selectedItems.Clear();
|
||||
selectedItems = View.Cast<object>().ToList();
|
||||
selectedItems = View.Cast<object>().ToList().Where(i => disabledPropertyGetter != null ? disabledPropertyGetter(i) as bool? != true : true).ToList();
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -292,10 +292,13 @@ namespace Radzen
|
||||
{
|
||||
if (LoadData.HasDelegate && !string.IsNullOrEmpty(ValueProperty))
|
||||
{
|
||||
return View != null && View.Cast<object>().All(i => IsItemSelectedByValue(GetItemOrValueFromProperty(i, ValueProperty)));
|
||||
return View != null && View.Cast<object>().ToList()
|
||||
.Where(i => disabledPropertyGetter != null ? disabledPropertyGetter(i) as bool? != true : true)
|
||||
.All(i => IsItemSelectedByValue(GetItemOrValueFromProperty(i, ValueProperty)));
|
||||
}
|
||||
|
||||
return View != null && selectedItems.Count == View.Cast<object>().Count();
|
||||
return View != null && selectedItems.Count == View.Cast<object>().ToList()
|
||||
.Where(i => disabledPropertyGetter != null ? disabledPropertyGetter(i) as bool? != true : true).Count();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -362,7 +365,7 @@ namespace Radzen
|
||||
selectedItem = null;
|
||||
selectedItems.Clear();
|
||||
}
|
||||
|
||||
|
||||
InvokeAsync(OnDataChanged);
|
||||
}
|
||||
}
|
||||
@@ -380,7 +383,7 @@ namespace Radzen
|
||||
var type = query.ElementType;
|
||||
|
||||
if (type == typeof(object) && typeof(EnumerableQuery).IsAssignableFrom(query.GetType()) && query.Any())
|
||||
{
|
||||
{
|
||||
type = query.FirstOrDefault().GetType();
|
||||
}
|
||||
|
||||
@@ -413,17 +416,26 @@ namespace Radzen
|
||||
/// <returns>System.Object.</returns>
|
||||
public object GetItemOrValueFromProperty(object item, string property)
|
||||
{
|
||||
if (property == TextProperty && textPropertyGetter != null)
|
||||
if (item != null)
|
||||
{
|
||||
return textPropertyGetter(item);
|
||||
}
|
||||
else if (property == ValueProperty && valuePropertyGetter != null)
|
||||
{
|
||||
return valuePropertyGetter(item);
|
||||
}
|
||||
else if (property == DisabledProperty && disabledPropertyGetter != null)
|
||||
{
|
||||
return disabledPropertyGetter(item);
|
||||
if (property == TextProperty && textPropertyGetter != null)
|
||||
{
|
||||
return textPropertyGetter(item);
|
||||
}
|
||||
else if (property == ValueProperty && valuePropertyGetter != null)
|
||||
{
|
||||
return valuePropertyGetter(item);
|
||||
}
|
||||
else if (property == DisabledProperty && disabledPropertyGetter != null)
|
||||
{
|
||||
return disabledPropertyGetter(item);
|
||||
}
|
||||
|
||||
var enumValue = item as Enum;
|
||||
if (enumValue != null)
|
||||
{
|
||||
return Radzen.Blazor.EnumExtensions.GetDisplayDescription(enumValue);
|
||||
}
|
||||
}
|
||||
|
||||
return item;
|
||||
@@ -595,7 +607,7 @@ namespace Radzen
|
||||
//
|
||||
}
|
||||
}
|
||||
else if (Multiple && key == "Space")
|
||||
else if (Multiple && key == "Enter")
|
||||
{
|
||||
if (selectedIndex >= 0 && selectedIndex <= items.Count() - 1)
|
||||
{
|
||||
@@ -836,7 +848,7 @@ namespace Radzen
|
||||
/// </summary>
|
||||
/// <param name="item">The item.</param>
|
||||
/// <returns><c>true</c> if the specified item is selected; otherwise, <c>false</c>.</returns>
|
||||
internal bool isSelected(object item)
|
||||
internal bool IsSelected(object item)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(ValueProperty))
|
||||
{
|
||||
@@ -987,6 +999,11 @@ namespace Radzen
|
||||
/// <param name="raiseChange">if set to <c>true</c> [raise change].</param>
|
||||
public async System.Threading.Tasks.Task SelectItem(object item, bool raiseChange = true)
|
||||
{
|
||||
if (disabledPropertyGetter != null && disabledPropertyGetter(item) as bool? == true)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Multiple)
|
||||
{
|
||||
if (object.Equals(item, selectedItem))
|
||||
@@ -995,7 +1012,7 @@ namespace Radzen
|
||||
selectedItem = item;
|
||||
if (!string.IsNullOrEmpty(ValueProperty))
|
||||
{
|
||||
internalValue = GetItemOrValueFromProperty(item, ValueProperty);
|
||||
internalValue = PropertyAccess.GetItemOrValueFromProperty(item, ValueProperty);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1080,7 +1097,7 @@ namespace Radzen
|
||||
}
|
||||
else
|
||||
{
|
||||
selectedItems = selectedItems.AsQueryable().Where($@"!object.Equals({ValueProperty},@0)", value).ToList();
|
||||
selectedItems = selectedItems.AsQueryable().Where($@"!object.Equals(it.{ValueProperty},@0)", value).ToList();
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -1146,7 +1163,7 @@ namespace Radzen
|
||||
item = View.AsQueryable().Where($@"{ValueProperty} == @0", v).FirstOrDefault();
|
||||
}
|
||||
|
||||
if (!object.Equals(item, null) && !selectedItems.AsQueryable().Where($@"object.Equals({ValueProperty},@0)", v).Any())
|
||||
if (!object.Equals(item, null) && !selectedItems.AsQueryable().Where($@"object.Equals(it.{ValueProperty},@0)", v).Any())
|
||||
{
|
||||
selectedItems.Add(item);
|
||||
}
|
||||
@@ -1168,20 +1185,17 @@ namespace Radzen
|
||||
|
||||
internal bool IsItemSelectedByValue(object v)
|
||||
{
|
||||
if (internalValue != null)
|
||||
switch (internalValue)
|
||||
{
|
||||
var values = internalValue as IEnumerable;
|
||||
if (values != null)
|
||||
{
|
||||
return values.Cast<object>().Contains(v);
|
||||
}
|
||||
else
|
||||
{
|
||||
case string s:
|
||||
return object.Equals(s, v);
|
||||
case IEnumerable enumerable:
|
||||
return enumerable.Cast<object>().Contains(v);
|
||||
case null:
|
||||
return false;
|
||||
default:
|
||||
return object.Equals(internalValue, v);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
22
Radzen.Blazor/Interpolation.cs
Normal file
22
Radzen.Blazor/Interpolation.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
namespace Radzen.Blazor
|
||||
{
|
||||
/// <summary>
|
||||
/// Specifies the interpolation mode of lines between data points. Used by <see cref="RadzenAreaSeries{TItem}"/> and <see cref="RadzenLineSeries{TItem}"/>.
|
||||
/// </summary>
|
||||
public enum Interpolation
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Points are connected by a straight line.
|
||||
/// </summary>
|
||||
Line,
|
||||
/// <summary>
|
||||
/// Points are connected by a smooth curve.
|
||||
/// </summary>
|
||||
Spline,
|
||||
/// <summary>
|
||||
/// Points are connected by horizontal and vertical lines only.
|
||||
/// </summary>
|
||||
Step
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2018-2022 Radzen Ltd
|
||||
Copyright (c) 2018-2023 Radzen Ltd
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
@@ -432,11 +432,11 @@ namespace Radzen
|
||||
}
|
||||
else if (PropertyAccess.IsNumeric(column.FilterPropertyType))
|
||||
{
|
||||
if (column.GetFilterOperator() == FilterOperator.IsNull || column.GetFilterOperator() == FilterOperator.IsNotNull)
|
||||
if (columnFilterOperator == FilterOperator.IsNull || columnFilterOperator == FilterOperator.IsNotNull)
|
||||
{
|
||||
return $"{property} {linqOperator} null";
|
||||
}
|
||||
else if (column.GetFilterOperator() == FilterOperator.IsEmpty || column.GetFilterOperator() == FilterOperator.IsNotEmpty)
|
||||
else if (columnFilterOperator == FilterOperator.IsEmpty || columnFilterOperator == FilterOperator.IsNotEmpty)
|
||||
{
|
||||
return $@"{property} {linqOperator} """"";
|
||||
}
|
||||
@@ -450,11 +450,11 @@ namespace Radzen
|
||||
column.FilterPropertyType == typeof(DateTimeOffset) ||
|
||||
column.FilterPropertyType == typeof(DateTimeOffset?))
|
||||
{
|
||||
if (column.GetFilterOperator() == FilterOperator.IsNull || column.GetFilterOperator() == FilterOperator.IsNotNull)
|
||||
if (columnFilterOperator == FilterOperator.IsNull || columnFilterOperator == FilterOperator.IsNotNull)
|
||||
{
|
||||
return $"{property} {linqOperator} null";
|
||||
}
|
||||
else if (column.GetFilterOperator() == FilterOperator.IsEmpty || column.GetFilterOperator() == FilterOperator.IsNotEmpty)
|
||||
else if (columnFilterOperator == FilterOperator.IsEmpty || columnFilterOperator == FilterOperator.IsNotEmpty)
|
||||
{
|
||||
return $@"{property} {linqOperator} """"";
|
||||
}
|
||||
@@ -474,11 +474,11 @@ namespace Radzen
|
||||
}
|
||||
else if (column.FilterPropertyType == typeof(Guid) || column.FilterPropertyType == typeof(Guid?))
|
||||
{
|
||||
if (column.GetFilterOperator() == FilterOperator.IsNull || column.GetFilterOperator() == FilterOperator.IsNotNull)
|
||||
if (columnFilterOperator == FilterOperator.IsNull || columnFilterOperator == FilterOperator.IsNotNull)
|
||||
{
|
||||
return $"{property} {linqOperator} null";
|
||||
}
|
||||
else if (column.GetFilterOperator() == FilterOperator.IsEmpty || column.GetFilterOperator() == FilterOperator.IsNotEmpty)
|
||||
else if (columnFilterOperator == FilterOperator.IsEmpty || columnFilterOperator == FilterOperator.IsNotEmpty)
|
||||
{
|
||||
return $@"{property} {linqOperator} """"";
|
||||
}
|
||||
@@ -1085,6 +1085,12 @@ namespace Radzen
|
||||
}
|
||||
else
|
||||
{
|
||||
if (filter.Property == null || (filter.FilterValue == null &&
|
||||
filter.FilterOperator != FilterOperator.IsNull && filter.FilterOperator != FilterOperator.IsNotNull))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var property = PropertyAccess.GetProperty(filter.Property);
|
||||
|
||||
if (property.IndexOf(".") != -1)
|
||||
@@ -1159,6 +1165,137 @@ namespace Radzen
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Converts to OData filter expression.
|
||||
/// </summary>
|
||||
/// <param name="dataFilter">The DataFilter.</param>
|
||||
/// <returns>System.String.</returns>
|
||||
public static string ToODataFilterString<T>(this RadzenDataFilter<T> dataFilter)
|
||||
{
|
||||
Func<CompositeFilterDescriptor, bool> canFilter = (c) => dataFilter.properties.Where(col => col.Property == c.Property).FirstOrDefault()?.FilterPropertyType != null &&
|
||||
(!(c.FilterValue == null || c.FilterValue as string == string.Empty)
|
||||
|| c.FilterOperator == FilterOperator.IsNotNull || c.FilterOperator == FilterOperator.IsNull
|
||||
|| c.FilterOperator == FilterOperator.IsEmpty || c.FilterOperator == FilterOperator.IsNotEmpty)
|
||||
&& c.Property != null;
|
||||
|
||||
if (dataFilter.Filters.Where(canFilter).Any())
|
||||
{
|
||||
var filterExpressions = new List<string>();
|
||||
|
||||
foreach (var filter in dataFilter.Filters)
|
||||
{
|
||||
AddODataExpression(canFilter, filter, ref filterExpressions, dataFilter);
|
||||
}
|
||||
|
||||
return filterExpressions.Any() ?
|
||||
string.Join($" {dataFilter.LogicalFilterOperator.ToString().ToLower()} ", filterExpressions)
|
||||
: "";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
private static void AddODataExpression<T>(Func<CompositeFilterDescriptor, bool> canFilter, CompositeFilterDescriptor filter, ref List<string> filterExpressions, RadzenDataFilter<T> dataFilter)
|
||||
{
|
||||
if (filter.Filters != null)
|
||||
{
|
||||
var innerFilterExpressions = new List<string>();
|
||||
|
||||
foreach (var f in filter.Filters)
|
||||
{
|
||||
AddODataExpression(canFilter, f, ref innerFilterExpressions, dataFilter);
|
||||
}
|
||||
|
||||
if (innerFilterExpressions.Any())
|
||||
{
|
||||
filterExpressions.Add("(" + string.Join($" {filter.LogicalFilterOperator.ToString().ToLower()} ", innerFilterExpressions) + ")");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (filter.Property == null || (filter.FilterValue == null &&
|
||||
filter.FilterOperator != FilterOperator.IsNull && filter.FilterOperator != FilterOperator.IsNotNull))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var property = filter.Property.Replace('.', '/');
|
||||
|
||||
var column = dataFilter.properties.Where(c => c.Property == filter.Property).FirstOrDefault();
|
||||
if (column == null) return;
|
||||
|
||||
if (dataFilter.FilterCaseSensitivity == FilterCaseSensitivity.CaseInsensitive && column.FilterPropertyType == typeof(string))
|
||||
{
|
||||
property = $"tolower({property})";
|
||||
}
|
||||
|
||||
if (filter.FilterOperator == FilterOperator.StartsWith || filter.FilterOperator == FilterOperator.EndsWith
|
||||
|| filter.FilterOperator == FilterOperator.Contains || filter.FilterOperator == FilterOperator.DoesNotContain)
|
||||
{
|
||||
if (IsEnumerable(column.FilterPropertyType) && column.FilterPropertyType != typeof(string) &&
|
||||
(filter.FilterOperator == FilterOperator.Contains || filter.FilterOperator == FilterOperator.DoesNotContain))
|
||||
{
|
||||
var enumerableValue = ((IEnumerable)(filter.FilterValue != null ? filter.FilterValue : Enumerable.Empty<object>())).AsQueryable();
|
||||
|
||||
var enumerableValueAsString = "(" + String.Join(",",
|
||||
(enumerableValue.ElementType == typeof(string) ? enumerableValue.Cast<string>().Select(i => $@"'{i}'").Cast<object>() : enumerableValue.Cast<object>())) + ")";
|
||||
|
||||
if (enumerableValue.Any() && filter.FilterOperator == FilterOperator.Contains)
|
||||
{
|
||||
filterExpressions.Add($"{property} in {enumerableValueAsString}");
|
||||
}
|
||||
else if (enumerableValue.Any() && filter.FilterOperator == FilterOperator.DoesNotContain)
|
||||
{
|
||||
filterExpressions.Add($"not({property} in {enumerableValueAsString})");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var expression = dataFilter.FilterCaseSensitivity == FilterCaseSensitivity.CaseInsensitive ?
|
||||
$"{ODataFilterOperators[filter.FilterOperator]}({property}, tolower('{filter.FilterValue}'))" :
|
||||
$"{ODataFilterOperators[filter.FilterOperator]}({property}, '{filter.FilterValue}')";
|
||||
|
||||
if (filter.FilterOperator == FilterOperator.DoesNotContain)
|
||||
{
|
||||
expression = $"not({expression})";
|
||||
}
|
||||
|
||||
filterExpressions.Add(expression);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (IsEnumerable(column.FilterPropertyType) && column.FilterPropertyType != typeof(string))
|
||||
return;
|
||||
|
||||
var value = $"{filter.FilterValue}";
|
||||
|
||||
if (filter.FilterOperator == FilterOperator.IsNull || filter.FilterOperator == FilterOperator.IsNotNull)
|
||||
{
|
||||
value = $"null";
|
||||
}
|
||||
else if (filter.FilterOperator == FilterOperator.IsEmpty || filter.FilterOperator == FilterOperator.IsNotEmpty)
|
||||
{
|
||||
value = $"''";
|
||||
}
|
||||
else if (column.FilterPropertyType == typeof(string))
|
||||
{
|
||||
value = $"'{value}'";
|
||||
}
|
||||
else if (column.FilterPropertyType == typeof(DateTime) || column.FilterPropertyType == typeof(DateTime?))
|
||||
{
|
||||
value = $"{DateTime.Parse(value, null, System.Globalization.DateTimeStyles.RoundtripKind).ToString("yyyy-MM-ddTHH:mm:ss.fffZ")}";
|
||||
}
|
||||
else if (column.FilterPropertyType == typeof(bool) || column.FilterPropertyType == typeof(bool?))
|
||||
{
|
||||
value = $"{value?.ToLower()}";
|
||||
}
|
||||
|
||||
filterExpressions.Add($@"{property} {ODataFilterOperators[filter.FilterOperator]} {value}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ases the o data enumerable.
|
||||
/// </summary>
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
Radzen Blazor Components are open source and free for commercial use. You can install them from [nuget](https://www.nuget.org/packages/Radzen.Blazor) or build your own copy from source.
|
||||
|
||||
Paid support is available as part of the [Radzen Professional subscription](https://www.radzen.com/pricing/).
|
||||
Paid support is available as part of the [Radzen Professional subscription](https://www.radzen.com/blazor-studio/pricing/).
|
||||
|
||||
### :computer: Native
|
||||
|
||||
@@ -31,10 +31,10 @@ Everybody is welcome to visit the [Radzen Community forum](https://forum.radzen.
|
||||
|
||||
The Radzen team monitors the forum threads, but does not guarantee a response to every question. For guaranteed responses you may consider the dedicated support option.
|
||||
|
||||
Dedicated support for the Radzen Blazor Components is available as part of the [Radzen Professional subscription](https://www.radzen.com/pricing/).
|
||||
Dedicated support for the Radzen Blazor Components is available as part of the [Radzen Professional subscription](https://www.radzen.com/blazor-studio/pricing/).
|
||||
|
||||
Our flagship product [Radzen Studio](https://www.radzen.com/features/) provides tons of productivity features for Blazor developers:
|
||||
- The first in the industry WYSIWYG Blazor design time canvas
|
||||
Our flagship product [Radzen Blazor Studio](https://www.radzen.com/blazor-studio/) provides tons of productivity features for Blazor developers:
|
||||
- An industry-leading WYSIWYG Blazor design time canvas
|
||||
- Scaffolding a complete CRUD applications from a database
|
||||
- Built-in security - authentication and authorization
|
||||
- Visual Studio Code and Professional support
|
||||
@@ -59,7 +59,7 @@ Radzen Blazor components come with five free themes: Material, Standard, Default
|
||||
|
||||
To use a theme
|
||||
1. Pick a theme. The [online demos](https://blazor.radzen.com/colors) allow you to preview the available options via the theme dropdown located in the header. The Material theme is currently selected by default.
|
||||
1. Include the theme CSS file in your Blazor application. Open `Pages\_Layout.cshtml` (Blazor Server .NET 6+), `Pages\_Host.cshtml` (Blazor Server before .NET 6) or `wwwroot/index.html` (Blazor WebAssembly) and include the CSS file of a theme CSS file by adding this snippet
|
||||
1. Include the theme CSS file in your Blazor application. Open `Pages\_Layout.cshtml` (Blazor Server .NET 6), `Pages\_Host.cshtml` (Blazor Server .NET 7) or `wwwroot/index.html` (Blazor WebAssembly) and include a theme CSS file by adding this snippet
|
||||
```html
|
||||
<link rel="stylesheet" href="_content/Radzen.Blazor/css/material-base.css">
|
||||
```
|
||||
@@ -71,7 +71,7 @@ To include a different theme (i.e. Standard) just change the name of the CSS fil
|
||||
|
||||
### 4. Include Radzen.Blazor.js
|
||||
|
||||
Open `Pages\_Layout.cshtml` (Blazor Server .NET 6+), `Pages\_Host.cshtml` (Blazor Server before .NET 6) or `wwwroot/index.html` (Blazor WebAssembly) and include this snippet:
|
||||
Open `Pages\_Layout.cshtml` (Blazor Server .NET 6), `Pages\_Host.cshtml` (Blazor Server .NET 7) or `wwwroot/index.html` (Blazor WebAssembly) and include this snippet:
|
||||
|
||||
```html
|
||||
<script src="_content/Radzen.Blazor/Radzen.Blazor.js"></script>
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<IsPackable>true</IsPackable>
|
||||
<PackageId>Radzen.Blazor</PackageId>
|
||||
<Product>Radzen.Blazor</Product>
|
||||
<Version>4.3.1</Version>
|
||||
<Version>4.6.7</Version>
|
||||
<Copyright>Radzen Ltd.</Copyright>
|
||||
<Authors>Radzen Ltd.</Authors>
|
||||
<Description>Radzen Blazor is a set of 70+ free native Blazor UI controls packed with DataGrid, Scheduler, Charts and robust theming including Material design and Fluent UI.</Description>
|
||||
@@ -32,7 +32,7 @@
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components" Condition="'$(TargetFramework)' == 'net7.0'" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.Web" Condition="'$(TargetFramework)' == 'net7.0'" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
|
||||
<PackageReference Include="System.Linq.Dynamic.Core" Version="1.2.12" />
|
||||
<PackageReference Include="System.Linq.Dynamic.Core" Version="1.2.22" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -10,14 +10,14 @@
|
||||
}
|
||||
@if (Visible)
|
||||
{
|
||||
<div @ref="@Element" role="tablist" @attributes="Attributes" class="@GetCssClass()" id="@GetId()">
|
||||
<div @ref="@Element" role="tablist" style=@Style @attributes="Attributes" class="@GetCssClass()" id="@GetId()">
|
||||
@for (var i = 0; i < items.Count; i++)
|
||||
{
|
||||
var item = items[i];
|
||||
if (!item.Visible)
|
||||
continue;
|
||||
|
||||
<div class="rz-accordion-header" @attributes="item.Attributes" style="@item.Style">
|
||||
<div @ref="@item.Element" id="@item.GetItemId()" @attributes="item.Attributes" class="@item.GetItemCssClass()" style="@item.Style">
|
||||
<a @onclick="@((args) => SelectItem(item))" href="javascript:void(0)" role="tab" tabindex="0"
|
||||
id="@($"rz-accordiontab-{items.IndexOf(item)}")" aria-controls="@($"rz-accordiontab-{items.IndexOf(item)}-content")" aria-expanded="true">
|
||||
@if (IsSelected(i, item))
|
||||
@@ -34,7 +34,7 @@
|
||||
}
|
||||
@if (!string.IsNullOrEmpty(item.Text))
|
||||
{
|
||||
<span>@item.Text</span>
|
||||
<span>@((MarkupString)item.Text)</span>
|
||||
}
|
||||
</a>
|
||||
</div>
|
||||
|
||||
@@ -109,5 +109,21 @@ namespace Radzen.Blazor
|
||||
|
||||
Accordion?.RemoveItem(this);
|
||||
}
|
||||
|
||||
internal string GetItemId()
|
||||
{
|
||||
return GetId();
|
||||
}
|
||||
|
||||
internal string GetItemCssClass()
|
||||
{
|
||||
return GetCssClass();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override string GetComponentCssClass()
|
||||
{
|
||||
return "rz-accordion-header";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,12 +8,20 @@
|
||||
<RadzenIcon Icon="@getIcon()" Class="rz-alert-icon" />
|
||||
}
|
||||
<div class="rz-alert-message">
|
||||
|
||||
@if (!string.IsNullOrEmpty(Title))
|
||||
{
|
||||
@if (!string.IsNullOrEmpty(Title))
|
||||
{
|
||||
<div class="rz-alert-title">@Title</div>
|
||||
}
|
||||
<div class="rz-alert-content">@ChildContent</div>
|
||||
}
|
||||
<div class="rz-alert-content">
|
||||
@if(ChildContent != null)
|
||||
{
|
||||
@ChildContent
|
||||
}
|
||||
else
|
||||
{
|
||||
@Text
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@if (AllowClose)
|
||||
|
||||
@@ -23,7 +23,7 @@ namespace Radzen.Blazor
|
||||
{
|
||||
return Size == AlertSize.Medium ? "md" : Size == AlertSize.Large ? "lg" : Size == AlertSize.Small ? "sm" : "xs";
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether close is allowed. Set to <c>true</c> by default.
|
||||
/// </summary>
|
||||
@@ -45,6 +45,13 @@ namespace Radzen.Blazor
|
||||
[Parameter]
|
||||
public string Title { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the text of the alert. Overriden by <see cref="ChildContent" />.
|
||||
/// </summary>
|
||||
/// <value>The title.</value>
|
||||
[Parameter]
|
||||
public string Text { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the icon.
|
||||
/// </summary>
|
||||
|
||||
@@ -12,16 +12,7 @@
|
||||
|
||||
var value = ComposeValue(valueScale);
|
||||
|
||||
IPathGenerator pathGenerator;
|
||||
|
||||
if (Smooth)
|
||||
{
|
||||
pathGenerator = new SplineGenerator();
|
||||
}
|
||||
else
|
||||
{
|
||||
pathGenerator = new LineGenerator();
|
||||
}
|
||||
var pathGenerator = GetPathGenerator();
|
||||
|
||||
var data = Items.Select(item =>
|
||||
{
|
||||
|
||||
@@ -42,7 +42,17 @@ namespace Radzen.Blazor
|
||||
/// Specifies whether to render a smooth line. Set to <c>false</c> by default.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public bool Smooth { get; set; }
|
||||
public bool Smooth
|
||||
{
|
||||
get => Interpolation == Interpolation.Spline;
|
||||
set => Interpolation = value ? Interpolation.Spline : Interpolation.Line;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Specifies how to render lines between data points. Set to <see cref="Line"/> by default
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public Interpolation Interpolation { get; set; } = Interpolation.Line;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string Color
|
||||
@@ -133,5 +143,20 @@ namespace Radzen.Blazor
|
||||
{
|
||||
return base.GetDataLabels(offsetX, offsetY - 16);
|
||||
}
|
||||
|
||||
private IPathGenerator GetPathGenerator()
|
||||
{
|
||||
switch(Interpolation)
|
||||
{
|
||||
case Interpolation.Line:
|
||||
return new LineGenerator();
|
||||
case Interpolation.Spline:
|
||||
return new SplineGenerator();
|
||||
case Interpolation.Step:
|
||||
return new StepGenerator();
|
||||
default:
|
||||
throw new NotSupportedException($"Interpolation {Interpolation} is not supported yet.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,7 +15,7 @@
|
||||
<textarea @ref="@search" @onkeydown="@OnFilterKeyPress" value="@Value" disabled="@Disabled"
|
||||
oninput="@OpenScript()" tabindex="@(Disabled ? "-1" : $"{TabIndex}")" @onchange="@OnChange"
|
||||
aria-autocomplete="list" aria-haspopup="true" autocomplete="off" role="combobox"
|
||||
class="@InputClassList"
|
||||
class="@InputClassList" onblur="Radzen.activeElement = null"
|
||||
id="@Name" aria-expanded="true" placeholder="@Placeholder" />
|
||||
}
|
||||
else
|
||||
@@ -23,7 +23,7 @@
|
||||
<input @ref="@search" @onkeydown="@OnFilterKeyPress" value="@Value" disabled="@Disabled"
|
||||
oninput="@OpenScript()" tabindex="@(Disabled ? "-1" : $"{TabIndex}")" @onchange="@OnChange"
|
||||
aria-autocomplete="list" aria-haspopup="true" autocomplete="off" role="combobox"
|
||||
class="@InputClassList"
|
||||
class="@InputClassList" onblur="Radzen.activeElement = null"
|
||||
type="text" id="@Name" aria-expanded="true" placeholder="@Placeholder" />
|
||||
}
|
||||
<div id="@PopupID" class="rz-autocomplete-panel" style="@PopupStyle">
|
||||
|
||||
@@ -38,10 +38,13 @@
|
||||
@donut.RenderTitle(MarginLeft, MarginTop)
|
||||
}
|
||||
}
|
||||
@if (tooltip != null)
|
||||
{
|
||||
@tooltip
|
||||
}
|
||||
<ChartTooltipContainer @ref="@chartTooltipContainer">
|
||||
@if (tooltip != null)
|
||||
{
|
||||
@tooltip
|
||||
}
|
||||
</ChartTooltipContainer>
|
||||
|
||||
</CascadingValue>
|
||||
}
|
||||
</div>
|
||||
|
||||
@@ -207,12 +207,7 @@ namespace Radzen.Blazor
|
||||
ValueScale.Fit(ValueAxis.TickDistance);
|
||||
CategoryScale.Fit(CategoryAxis.TickDistance);
|
||||
|
||||
var stateHasChanged = false;
|
||||
|
||||
if (!ValueScale.IsEqualTo(valueScale))
|
||||
{
|
||||
stateHasChanged = true;
|
||||
}
|
||||
var stateHasChanged = !ValueScale.IsEqualTo(valueScale);
|
||||
|
||||
if (!CategoryScale.IsEqualTo(categoryScale))
|
||||
{
|
||||
@@ -254,6 +249,7 @@ namespace Radzen.Blazor
|
||||
}
|
||||
}
|
||||
|
||||
ChartTooltipContainer chartTooltipContainer;
|
||||
RenderFragment tooltip;
|
||||
object tooltipData;
|
||||
double mouseX;
|
||||
@@ -313,7 +309,7 @@ namespace Radzen.Blazor
|
||||
{
|
||||
tooltipData = null;
|
||||
tooltip = overlay.RenderTooltip(mouseX, mouseY, MarginLeft, MarginTop);
|
||||
StateHasChanged();
|
||||
chartTooltipContainer.Refresh();
|
||||
await Task.Yield();
|
||||
|
||||
return;
|
||||
@@ -328,7 +324,7 @@ namespace Radzen.Blazor
|
||||
{
|
||||
tooltipData = data;
|
||||
tooltip = series.RenderTooltip(data, MarginLeft, MarginTop);
|
||||
StateHasChanged();
|
||||
chartTooltipContainer.Refresh();
|
||||
await Task.Yield();
|
||||
}
|
||||
|
||||
@@ -342,7 +338,7 @@ namespace Radzen.Blazor
|
||||
tooltipData = null;
|
||||
tooltip = null;
|
||||
|
||||
StateHasChanged();
|
||||
chartTooltipContainer.Refresh();
|
||||
await Task.Yield();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
}
|
||||
@foreach (var item in allItems.Where(i => i.Visible))
|
||||
{
|
||||
<div class="rz-checkbox" @onclick="@(args => SelectItem(item))" @attributes="item.Attributes" style="@item.Style">
|
||||
<div @ref="@item.Element" id="@item.GetItemId()" @onclick="@(args => SelectItem(item))" @attributes="item.Attributes" class="@item.GetItemCssClass()" style="@item.Style">
|
||||
<div class="rz-chkbox " @onkeypress="@(async args => { if (args.Code == "Space") { await SelectItem(item); } })" tabindex="@(Disabled || item.Disabled ? "-1" : $"{TabIndex}")">
|
||||
<div class="rz-helper-hidden-accessible">
|
||||
<input type="checkbox" name="@Name" value="@item.Value" disabled="@Disabled" tabindex="-1">
|
||||
|
||||
@@ -70,5 +70,20 @@ namespace Radzen.Blazor
|
||||
{
|
||||
Value = value;
|
||||
}
|
||||
internal string GetItemId()
|
||||
{
|
||||
return GetId();
|
||||
}
|
||||
|
||||
internal string GetItemCssClass()
|
||||
{
|
||||
return GetCssClass();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override string GetComponentCssClass()
|
||||
{
|
||||
return "rz-checkbox";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -366,7 +366,8 @@ namespace Radzen.Blazor
|
||||
void Init()
|
||||
{
|
||||
var value = Value;
|
||||
if (String.IsNullOrEmpty(Value))
|
||||
|
||||
if (String.IsNullOrEmpty(Value) || RGB.Parse(Value) == null)
|
||||
{
|
||||
value = "rgb(255, 255, 255)";
|
||||
}
|
||||
|
||||
6
Radzen.Blazor/RadzenColumn.razor
Normal file
6
Radzen.Blazor/RadzenColumn.razor
Normal file
@@ -0,0 +1,6 @@
|
||||
@inherits RadzenComponentWithChildren
|
||||
|
||||
@if (Visible)
|
||||
{
|
||||
<div @ref="@Element" @attributes="Attributes" class="@GetCssClass()" style="@GetStyle()" id="@GetId()">@ChildContent</div>
|
||||
}
|
||||
245
Radzen.Blazor/RadzenColumn.razor.cs
Normal file
245
Radzen.Blazor/RadzenColumn.razor.cs
Normal file
@@ -0,0 +1,245 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Radzen.Blazor
|
||||
{
|
||||
/// <summary>
|
||||
/// RadzenColumn component.
|
||||
/// </summary>
|
||||
public partial class RadzenColumn : RadzenComponentWithChildren
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the size.
|
||||
/// </summary>
|
||||
/// <value>The size.</value>
|
||||
[Parameter]
|
||||
public int? Size { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the XS size.
|
||||
/// </summary>
|
||||
/// <value>The XS size.</value>
|
||||
[Parameter]
|
||||
public int? SizeXS { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the SM size.
|
||||
/// </summary>
|
||||
/// <value>The SM size.</value>
|
||||
[Parameter]
|
||||
public int? SizeSM { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the MD size.
|
||||
/// </summary>
|
||||
/// <value>The MD size.</value>
|
||||
[Parameter]
|
||||
public int? SizeMD { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the LG size.
|
||||
/// </summary>
|
||||
/// <value>The LG size.</value>
|
||||
[Parameter]
|
||||
public int? SizeLG { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the XL size.
|
||||
/// </summary>
|
||||
/// <value>The XL size.</value>
|
||||
[Parameter]
|
||||
public int? SizeXL { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the XX size.
|
||||
/// </summary>
|
||||
/// <value>The XX size.</value>
|
||||
[Parameter]
|
||||
public int? SizeXX { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the offset.
|
||||
/// </summary>
|
||||
/// <value>The offset.</value>
|
||||
[Parameter]
|
||||
public int? Offset { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the XS offset.
|
||||
/// </summary>
|
||||
/// <value>The XS offset.</value>
|
||||
[Parameter]
|
||||
public int? OffsetXS { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the SM offset.
|
||||
/// </summary>
|
||||
/// <value>The SM offset.</value>
|
||||
[Parameter]
|
||||
public int? OffsetSM { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the MD offset.
|
||||
/// </summary>
|
||||
/// <value>The MD offset.</value>
|
||||
[Parameter]
|
||||
public int? OffsetMD { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the LG offset.
|
||||
/// </summary>
|
||||
/// <value>The LG offset.</value>
|
||||
[Parameter]
|
||||
public int? OffsetLG { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the XL offset.
|
||||
/// </summary>
|
||||
/// <value>The XL offset.</value>
|
||||
[Parameter]
|
||||
public int? OffsetXL { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the XX offset.
|
||||
/// </summary>
|
||||
/// <value>The XX offset.</value>
|
||||
[Parameter]
|
||||
public int? OffsetXX { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the order.
|
||||
/// </summary>
|
||||
/// <value>The order.</value>
|
||||
[Parameter]
|
||||
public string Order { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the XS order.
|
||||
/// </summary>
|
||||
/// <value>The XS order.</value>
|
||||
[Parameter]
|
||||
public string OrderXS { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the SM order.
|
||||
/// </summary>
|
||||
/// <value>The SM order.</value>
|
||||
[Parameter]
|
||||
public string OrderSM { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the MD order.
|
||||
/// </summary>
|
||||
/// <value>The MD order.</value>
|
||||
[Parameter]
|
||||
public string OrderMD { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the LG order.
|
||||
/// </summary>
|
||||
/// <value>The LG order.</value>
|
||||
[Parameter]
|
||||
public string OrderLG { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the XL order.
|
||||
/// </summary>
|
||||
/// <value>The XL order.</value>
|
||||
[Parameter]
|
||||
public string OrderXL { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the XX order.
|
||||
/// </summary>
|
||||
/// <value>The XX order.</value>
|
||||
[Parameter]
|
||||
public string OrderXX { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the final CSS style rendered by the component. Combines it with a <c>style</c> custom attribute.
|
||||
/// </summary>
|
||||
protected string GetStyle()
|
||||
{
|
||||
if (Attributes != null && Attributes.TryGetValue("style", out var style) && !string.IsNullOrEmpty(Convert.ToString(@style)))
|
||||
{
|
||||
return $"{GetComponentStyle()} {@style}";
|
||||
}
|
||||
|
||||
return GetComponentStyle();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the component CSS style.
|
||||
/// </summary>
|
||||
protected string GetComponentStyle()
|
||||
{
|
||||
return $"{Style}{(!string.IsNullOrEmpty(Style) && !Style.EndsWith(";") ? ";" : "")}";
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override string GetComponentCssClass()
|
||||
{
|
||||
var list = new List<string>
|
||||
{
|
||||
Size != null ? $"rz-col-{GetColumnValue("Size", Size)}" : "rz-col"
|
||||
};
|
||||
|
||||
if (Offset != null)
|
||||
{
|
||||
list.Add($"rz-offset-{GetColumnValue("Offset", Offset)}");
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(Order))
|
||||
{
|
||||
list.Add($"rz-order-{GetOrderValue("Order", Order)}");
|
||||
}
|
||||
|
||||
var breakPoints = new string[] { "xs", "sm", "md", "lg", "xl", "xx" };
|
||||
|
||||
var properties = GetType().GetProperties()
|
||||
.Where(p => breakPoints.Any(bp => p.Name.ToLower().EndsWith(bp)))
|
||||
.Select(p => new { p.Name, BreakPoint = string.Concat(p.Name.ToLower().TakeLast(2)), Value = p.GetValue(this) });
|
||||
|
||||
foreach (var p in properties)
|
||||
{
|
||||
if (p.Value != null)
|
||||
{
|
||||
list.Add($"rz-{(!p.Name.StartsWith("Size") ? p.Name.ToLower().Replace(p.BreakPoint, "") + "-" : "col-")}{p.BreakPoint}-{GetColumnValue(p.Name, p.Value)}");
|
||||
}
|
||||
}
|
||||
|
||||
return string.Join(" ", list);
|
||||
}
|
||||
|
||||
string GetColumnValue(string name, object value)
|
||||
{
|
||||
if (name.StartsWith("Order"))
|
||||
{
|
||||
return GetOrderValue(name, value.ToString());
|
||||
}
|
||||
|
||||
if ((int)value < 0 || (int)value > 12)
|
||||
{
|
||||
throw new Exception($"Property {name} value should be between 0 and 12.");
|
||||
}
|
||||
|
||||
return $"{value}";
|
||||
}
|
||||
|
||||
string GetOrderValue(string name, string value)
|
||||
{
|
||||
var orders = Enumerable.Range(0, 12).Select(i => $"{i}").ToArray().Concat(new string[] { "first", "last" });
|
||||
|
||||
if (!orders.Contains(value))
|
||||
{
|
||||
throw new Exception($"Property {name} value should be between 0 and 12 or first/last.");
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -42,7 +42,7 @@ else
|
||||
@if (property.FilterTemplate != null)
|
||||
{
|
||||
<div class="rz-datafilter-editor" style="display:flex">
|
||||
@property.FilterTemplate(property)
|
||||
@property.FilterTemplate(Filter)
|
||||
</div>
|
||||
}
|
||||
else if (PropertyAccess.IsNullableEnum(property.FilterPropertyType) || PropertyAccess.IsEnum(property.FilterPropertyType))
|
||||
@@ -102,7 +102,11 @@ else
|
||||
property.FilterValueChange += OnFilterValueChange;
|
||||
|
||||
Filter.Property = property.Property;
|
||||
Filter.FilterOperator = property.GetFilterOperator();
|
||||
|
||||
if (!property.GetFilterOperators().Contains(Filter.FilterOperator))
|
||||
{
|
||||
Filter.FilterOperator = property.GetFilterOperators().FirstOrDefault();
|
||||
}
|
||||
|
||||
var v = property.GetFilterValue();
|
||||
if (v != null)
|
||||
@@ -246,15 +250,7 @@ else
|
||||
{
|
||||
if (property != null && !string.IsNullOrEmpty(property.FormatString))
|
||||
{
|
||||
var formats = property.FormatString.Split(new char[] { '{', '}' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
if (formats.Length > 0)
|
||||
{
|
||||
var format = formats[0].Trim().Split(':');
|
||||
if (format.Length > 1)
|
||||
{
|
||||
return format[1].Trim();
|
||||
}
|
||||
}
|
||||
return property.FormatString.Replace("{0:", "").Replace("}", "");
|
||||
}
|
||||
|
||||
return DataFilter.FilterDateFormat;
|
||||
|
||||
@@ -130,7 +130,7 @@ namespace Radzen.Blazor
|
||||
/// </summary>
|
||||
/// <value>The filter template.</value>
|
||||
[Parameter]
|
||||
public RenderFragment<RadzenDataFilterProperty<TItem>> FilterTemplate { get; set; }
|
||||
public RenderFragment<CompositeFilterDescriptor> FilterTemplate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the data type.
|
||||
@@ -293,10 +293,26 @@ namespace Radzen.Blazor
|
||||
if (PropertyAccess.IsNullableEnum(FilterPropertyType))
|
||||
return new FilterOperator[] { FilterOperator.Equals, FilterOperator.NotEquals, FilterOperator.IsNull, FilterOperator.IsNotNull };
|
||||
|
||||
if ((typeof(IEnumerable).IsAssignableFrom(FilterPropertyType) || typeof(IEnumerable<>).IsAssignableFrom(FilterPropertyType))
|
||||
&& FilterPropertyType != typeof(string))
|
||||
{
|
||||
return new FilterOperator[]
|
||||
{
|
||||
FilterOperator.Contains,
|
||||
FilterOperator.DoesNotContain,
|
||||
FilterOperator.Equals,
|
||||
FilterOperator.NotEquals,
|
||||
FilterOperator.IsNull,
|
||||
FilterOperator.IsNotNull,
|
||||
FilterOperator.IsEmpty,
|
||||
FilterOperator.IsNotEmpty
|
||||
};
|
||||
}
|
||||
|
||||
return Enum.GetValues(typeof(FilterOperator)).Cast<FilterOperator>().Where(o => {
|
||||
var isStringOperator = o == FilterOperator.Contains || o == FilterOperator.DoesNotContain
|
||||
|| o == FilterOperator.StartsWith || o == FilterOperator.EndsWith || o == FilterOperator.IsEmpty || o == FilterOperator.IsNotEmpty;
|
||||
return FilterPropertyType == typeof(string) || typeof(IEnumerable).IsAssignableFrom(FilterPropertyType) || typeof(IEnumerable<>).IsAssignableFrom(FilterPropertyType) ? isStringOperator
|
||||
return FilterPropertyType == typeof(string) ? isStringOperator
|
||||
|| o == FilterOperator.Equals || o == FilterOperator.NotEquals
|
||||
|| o == FilterOperator.IsNull || o == FilterOperator.IsNotNull
|
||||
: !isStringOperator;
|
||||
|
||||
@@ -64,7 +64,7 @@
|
||||
}
|
||||
|
||||
<div class="rz-data-grid-data">
|
||||
<table class="rz-grid-table rz-grid-table-fixed @(AllowAlternatingRows ? "rz-grid-table-striped" : "") @(allColumns.Any(c => c.Parent != null) ? "rz-grid-table-composite" : "")">
|
||||
<table class="rz-grid-table rz-grid-table-fixed @(AllowAlternatingRows ? "rz-grid-table-striped" : "") @(allColumns.Any(c => c.Parent != null) ? "rz-grid-table-composite" : "") @(getGridLinesCSSClass())">
|
||||
<colgroup>
|
||||
@foreach(var g in Groups)
|
||||
{
|
||||
@@ -89,7 +89,7 @@
|
||||
<span class="rz-column-title"></span>
|
||||
</th>
|
||||
}
|
||||
@if (Template != null && ShowExpandColumn)
|
||||
@if (Template != null && ShowExpandColumn && i == 0)
|
||||
{
|
||||
<th class="rz-col-icon rz-unselectable-text" scope="col" rowspan=@(deepestChildColumnLevel + 1)>
|
||||
<span class="rz-column-title"></span>
|
||||
@@ -112,7 +112,7 @@
|
||||
var columnIndex = visibleColumns.IndexOf(column);
|
||||
var sortableClass = AllowSorting && column.Sortable ? "rz-sortable-column" : "";
|
||||
|
||||
<RadzenDataGridHeaderCell RowIndex="@i" Grid="@this" Column="@column" ColumnIndex="@columnIndex" CssClass="@($"rz-unselectable-text {sortableClass} {column.HeaderCssClass} {getFrozenColumnClass(column, visibleColumns)} {(column.Columns != null || column.Parent != null ? "rz-composite-cell" : "")} {getColumnAlignClass(column)}".Trim())" Attributes="@(cellAttr)" />
|
||||
<RadzenDataGridHeaderCell RowIndex="@i" Grid="@this" Column="@column" ColumnIndex="@columnIndex" CssClass="@($"rz-unselectable-text {sortableClass} {column.HeaderCssClass} {getFrozenColumnClass(column, visibleColumns)} {getCompositeCellCSSClass(column)} {getColumnAlignClass(column)}".Trim())" Attributes="@(cellAttr)" />
|
||||
}
|
||||
</tr>
|
||||
}
|
||||
@@ -133,7 +133,7 @@
|
||||
}
|
||||
@foreach (var column in visibleColumns)
|
||||
{
|
||||
<th colspan="@column.GetColSpan()" class="@($"rz-unselectable-text {getFrozenColumnClass(column, visibleColumns)}")" scope="col" style="@column.GetStyle(true, true)">
|
||||
<th colspan="@column.GetColSpan()" class="@($"rz-unselectable-text {getFrozenColumnClass(column, visibleColumns)} {column.HeaderCssClass}")" scope="col" style="@column.GetStyle(true, true)">
|
||||
@if (AllowFiltering && column.Filterable && column.Columns == null && (!string.IsNullOrEmpty(column.GetFilterProperty()) || column.FilterTemplate != null))
|
||||
{
|
||||
<div class="rz-cell-filter">
|
||||
@@ -302,7 +302,7 @@
|
||||
<tbody>
|
||||
@if (Data != null)
|
||||
{
|
||||
@if (!ShowEmptyMessage || Count > 0 || !AllowPaging && LoadData.HasDelegate && Count == 0)
|
||||
@if (!ShowEmptyMessage || Count > 0 && (IsVirtualizationAllowed() ? Data.Any() : true) || !AllowPaging && LoadData.HasDelegate && Count == 0)
|
||||
{
|
||||
if (columns.Count > 0)
|
||||
{
|
||||
@@ -312,7 +312,7 @@
|
||||
else
|
||||
{
|
||||
<tr class=" rz-datatable-emptymessage-row">
|
||||
<td class="rz-datatable-emptymessage" colspan="@(visibleColumns.Count + (Template != null && ShowExpandColumn ? 1 : 0))">
|
||||
<td class="rz-datatable-emptymessage" colspan="@(visibleColumns.Sum(c => c.GetColSpan()) + (Template != null && ShowExpandColumn ? 1 : 0))">
|
||||
@if (EmptyTemplate != null)
|
||||
{
|
||||
@EmptyTemplate
|
||||
@@ -338,7 +338,7 @@
|
||||
<span class="rz-column-title"></span>
|
||||
</td>
|
||||
}
|
||||
@if (Template != null && ShowExpandColumn)
|
||||
@if (Template != null && ShowExpandColumn && i == 0)
|
||||
{
|
||||
<td class="rz-col-icon rz-unselectable-text" scope="col" rowspan=@(deepestChildColumnLevel + 1)>
|
||||
<span class="rz-column-title"></span>
|
||||
@@ -358,7 +358,7 @@
|
||||
}
|
||||
|
||||
<RadzenDataGridFooterCell RowIndex="@i" Grid="@this" Column="@column"
|
||||
CssClass="@($"{column.FooterCssClass} {getFrozenColumnClass(column, visibleColumns)} {(column.Columns != null || column.Parent != null ? "rz-composite-cell" : "")}".Trim())"
|
||||
CssClass="@($"{column.FooterCssClass} {getFrozenColumnClass(column, visibleColumns)} {getCompositeCellCSSClass(column)}".Trim())"
|
||||
Attributes="@(cellAttr)" />
|
||||
}
|
||||
</tr>
|
||||
|
||||
@@ -31,6 +31,19 @@ namespace Radzen.Blazor
|
||||
public partial class RadzenDataGrid<TItem> : PagedDataBoundComponent<TItem>
|
||||
{
|
||||
#if NET5_0_OR_GREATER
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether this instance is virtualized.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if this instance is virtualized; otherwise, <c>false</c>.</value>
|
||||
[Parameter]
|
||||
public bool AllowVirtualization { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value that determines how many additional items will be rendered before and after the visible region. This help to reduce the frequency of rendering during scrolling. However, higher values mean that more elements will be present in the page.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public int VirtualizationOverscanCount { get; set; }
|
||||
|
||||
internal void SetAllowVirtualization(bool allowVirtualization)
|
||||
{
|
||||
AllowVirtualization = allowVirtualization;
|
||||
@@ -66,7 +79,7 @@ namespace Radzen.Blazor
|
||||
|
||||
var totalItemsCount = LoadData.HasDelegate ? Count : view.Count();
|
||||
|
||||
virtualDataItems = (LoadData.HasDelegate ? Data : itemToInsert != null ? (new[] { itemToInsert }).Concat(view.Skip(request.StartIndex).Take(top)) : view.Skip(request.StartIndex).Take(top)).ToList();
|
||||
virtualDataItems = (LoadData.HasDelegate ? Data : itemToInsert != null ? (new[] { itemToInsert }).Concat(view.Skip(request.StartIndex).Take(top)) : view.Skip(request.StartIndex).Take(top))?.ToList();
|
||||
|
||||
return new Microsoft.AspNetCore.Components.Web.Virtualization.ItemsProviderResult<TItem>(virtualDataItems, totalItemsCount);
|
||||
}
|
||||
@@ -144,6 +157,11 @@ namespace Radzen.Blazor
|
||||
});
|
||||
}));
|
||||
|
||||
if(VirtualizationOverscanCount != default(int))
|
||||
{
|
||||
builder.AddAttribute(1, "OverscanCount", VirtualizationOverscanCount);
|
||||
}
|
||||
|
||||
builder.AddComponentReferenceCapture(8, c => { virtualize = (Microsoft.AspNetCore.Components.Web.Virtualization.Virtualize<TItem>)c; });
|
||||
|
||||
}
|
||||
@@ -386,7 +404,7 @@ namespace Radzen.Blazor
|
||||
var descriptor = sorts.Where(d => d.Property == column?.GetSortProperty()).FirstOrDefault();
|
||||
if (descriptor == null && column.SortOrder.HasValue)
|
||||
{
|
||||
descriptor = new SortDescriptor() { Property = column.Property, SortOrder = column.SortOrder.Value };
|
||||
descriptor = new SortDescriptor() { Property = column.GetSortProperty(), SortOrder = column.SortOrder.Value };
|
||||
sorts.Add(descriptor);
|
||||
}
|
||||
|
||||
@@ -484,15 +502,7 @@ namespace Radzen.Blazor
|
||||
{
|
||||
if (column != null && !string.IsNullOrEmpty(column.FormatString))
|
||||
{
|
||||
var formats = column.FormatString.Split(new char[] { '{', '}' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
if (formats.Length > 0)
|
||||
{
|
||||
var format = formats[0].Trim().Split(':');
|
||||
if (format.Length > 1)
|
||||
{
|
||||
return format[1].Trim();
|
||||
}
|
||||
}
|
||||
return column.FormatString.Replace("{0:", "").Replace("}", "");
|
||||
}
|
||||
|
||||
return FilterDateFormat;
|
||||
@@ -665,6 +675,13 @@ namespace Radzen.Blazor
|
||||
[Parameter]
|
||||
public EventCallback<DataGridColumnFilterEventArgs<TItem>> FilterCleared { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the render mode.
|
||||
/// </summary>
|
||||
/// <value>The render mode.</value>
|
||||
[Parameter]
|
||||
public PopupRenderMode FilterPopupRenderMode { get; set; } = PopupRenderMode.Initial;
|
||||
|
||||
internal async Task ClearFilter(RadzenDataGridColumn<TItem> column, bool closePopup = false)
|
||||
{
|
||||
if (closePopup)
|
||||
@@ -995,14 +1012,7 @@ namespace Radzen.Blazor
|
||||
/// <value>The empty template.</value>
|
||||
[Parameter]
|
||||
public RenderFragment EmptyTemplate { get; set; }
|
||||
#if NET5_0_OR_GREATER
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether this instance is virtualized.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if this instance is virtualized; otherwise, <c>false</c>.</value>
|
||||
[Parameter]
|
||||
public bool AllowVirtualization { get; set; }
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether this instance loading indicator is shown.
|
||||
/// </summary>
|
||||
@@ -1059,6 +1069,13 @@ namespace Radzen.Blazor
|
||||
[Parameter]
|
||||
public bool AllowColumnPicking { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether cell data should be shown as tooltip.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if cell data is shown as tooltip; otherwise, <c>false</c>.</value>
|
||||
[Parameter]
|
||||
public bool ShowCellDataAsTooltip { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the column picker columns showing text.
|
||||
/// </summary>
|
||||
@@ -1142,7 +1159,7 @@ namespace Radzen.Blazor
|
||||
|
||||
internal async Task EndColumnReorder(MouseEventArgs args, int columnIndex)
|
||||
{
|
||||
if (indexOfColumnToReoder != null)
|
||||
if (indexOfColumnToReoder != null && AllowColumnReorder)
|
||||
{
|
||||
var visibleColumns = columns.Where(c => c.GetVisible()).ToList();
|
||||
var columnToReorder = visibleColumns.ElementAtOrDefault(indexOfColumnToReoder.Value);
|
||||
@@ -1213,6 +1230,60 @@ namespace Radzen.Blazor
|
||||
[Parameter]
|
||||
public EventCallback<DataGridColumnReorderedEventArgs<TItem>> ColumnReordered { get; set; }
|
||||
|
||||
IQueryable<TItem> GetSelfRefView(IQueryable<TItem> view, string orderBy)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(orderBy))
|
||||
{
|
||||
if (typeof(TItem) == typeof(object))
|
||||
{
|
||||
var firstItem = view.FirstOrDefault();
|
||||
if (firstItem != null)
|
||||
{
|
||||
view = view.Cast(firstItem.GetType()).AsQueryable().OrderBy(orderBy).Cast<TItem>();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
view = view.OrderBy(orderBy);
|
||||
}
|
||||
}
|
||||
|
||||
var viewList = view.ToList();
|
||||
var countWithChildren = viewList.Count + childData.SelectMany(d => d.Value.Data).Count();
|
||||
|
||||
for (int i = 0; i < countWithChildren; i++)
|
||||
{
|
||||
var item = viewList.ElementAtOrDefault(i);
|
||||
|
||||
if (item != null && childData.ContainsKey(item))
|
||||
{
|
||||
var level = 1;
|
||||
var parentChildData = childData[item].ParentChildData;
|
||||
while (parentChildData != null)
|
||||
{
|
||||
parentChildData = parentChildData.ParentChildData;
|
||||
level++;
|
||||
}
|
||||
|
||||
childData[item].Level = level;
|
||||
|
||||
var cd = childData[item].Data.AsQueryable();
|
||||
if (!string.IsNullOrEmpty(orderBy))
|
||||
{
|
||||
cd = cd.OrderBy(orderBy);
|
||||
}
|
||||
|
||||
viewList.InsertRange(viewList.IndexOf(item) + 1, cd);
|
||||
}
|
||||
}
|
||||
|
||||
view = viewList.AsQueryable()
|
||||
.Where(i => childData.ContainsKey(i) && childData[i].Data.AsQueryable().Where<TItem>(allColumns).Any()
|
||||
|| viewList.AsQueryable().Where<TItem>(allColumns).Contains(i));
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the view - Data with sorting, filtering and paging applied.
|
||||
/// </summary>
|
||||
@@ -1221,66 +1292,26 @@ namespace Radzen.Blazor
|
||||
{
|
||||
get
|
||||
{
|
||||
if(LoadData.HasDelegate)
|
||||
var orderBy = GetOrderBy();
|
||||
|
||||
if (LoadData.HasDelegate)
|
||||
{
|
||||
return base.View;
|
||||
if (childData.Any())
|
||||
{
|
||||
return GetSelfRefView(base.View, orderBy);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
return base.View;
|
||||
}
|
||||
}
|
||||
|
||||
IQueryable<TItem> view;
|
||||
var orderBy = GetOrderBy();
|
||||
|
||||
if (childData.Any())
|
||||
{
|
||||
view = base.View;//.Where<TItem>(allColumns);
|
||||
|
||||
if (!string.IsNullOrEmpty(orderBy))
|
||||
{
|
||||
if (typeof(TItem) == typeof(object))
|
||||
{
|
||||
var firstItem = view.FirstOrDefault();
|
||||
if (firstItem != null)
|
||||
{
|
||||
view = view.Cast(firstItem.GetType()).AsQueryable().OrderBy(orderBy).Cast<TItem>();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
view = view.OrderBy(orderBy);
|
||||
}
|
||||
}
|
||||
|
||||
var viewList = view.ToList();
|
||||
var countWithChildren = viewList.Count + childData.SelectMany(d => d.Value.Data).Count();
|
||||
|
||||
for (int i = 0; i < countWithChildren; i++)
|
||||
{
|
||||
var item = viewList.ElementAtOrDefault(i);
|
||||
|
||||
if (item != null && childData.ContainsKey(item))
|
||||
{
|
||||
var level = 1;
|
||||
var parentChildData = childData[item].ParentChildData;
|
||||
while (parentChildData != null)
|
||||
{
|
||||
parentChildData = parentChildData.ParentChildData;
|
||||
level++;
|
||||
}
|
||||
|
||||
childData[item].Level = level;
|
||||
|
||||
var cd = childData[item].Data.AsQueryable();
|
||||
if (!string.IsNullOrEmpty(orderBy))
|
||||
{
|
||||
cd = cd.OrderBy(orderBy);
|
||||
}
|
||||
|
||||
viewList.InsertRange(viewList.IndexOf(item) + 1, cd);
|
||||
}
|
||||
}
|
||||
|
||||
view = viewList.AsQueryable()
|
||||
.Where(i => childData.ContainsKey(i) && childData[i].Data.AsQueryable().Where<TItem>(allColumns).Any()
|
||||
|| viewList.AsQueryable().Where<TItem>(allColumns).Contains(i));
|
||||
view = GetSelfRefView(base.View, orderBy);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1529,6 +1560,8 @@ namespace Radzen.Blazor
|
||||
});
|
||||
sorts.Clear();
|
||||
}
|
||||
|
||||
SaveSettings();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1667,11 +1700,30 @@ namespace Radzen.Blazor
|
||||
return !collapsedGroupItems.Keys.Contains(item);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether all groups should be expanded when DataGrid is grouped.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if groups are expanded; otherwise, <c>false</c>.</value>
|
||||
[Parameter]
|
||||
public bool? AllGroupsExpanded { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the AllGroupsExpanded changed callback.
|
||||
/// </summary>
|
||||
/// <value>The AllGroupsExpanded changed callback.</value>
|
||||
[Parameter]
|
||||
public EventCallback<bool?> AllGroupsExpandedChanged { get; set; }
|
||||
|
||||
internal bool? allGroupsExpanded;
|
||||
|
||||
internal async System.Threading.Tasks.Task ExpandGroupItem(RadzenDataGridGroupRow<TItem> item, bool? expandedOnLoad)
|
||||
{
|
||||
if (expandedOnLoad == true)
|
||||
return;
|
||||
|
||||
allGroupsExpanded = null;
|
||||
await AllGroupsExpandedChanged.InvokeAsync(allGroupsExpanded);
|
||||
|
||||
if (!collapsedGroupItems.Keys.Contains(item))
|
||||
{
|
||||
await GroupRowCollapse.InvokeAsync(item.Group);
|
||||
@@ -1733,15 +1785,20 @@ namespace Radzen.Blazor
|
||||
public override async Task SetParametersAsync(ParameterView parameters)
|
||||
{
|
||||
var emptyTextChanged = parameters.DidParameterChange(nameof(EmptyText), EmptyText);
|
||||
if (emptyTextChanged)
|
||||
{
|
||||
await ChangeState();
|
||||
}
|
||||
|
||||
var allowColumnPickingChanged = parameters.DidParameterChange(nameof(AllowColumnPicking), AllowColumnPicking);
|
||||
|
||||
visibleChanged = parameters.DidParameterChange(nameof(Visible), Visible);
|
||||
|
||||
bool valueChanged = parameters.DidParameterChange(nameof(Value), Value);
|
||||
|
||||
|
||||
var allGroupsExpandedChanged = parameters.DidParameterChange(nameof(AllGroupsExpanded), AllGroupsExpanded);
|
||||
if (allGroupsExpandedChanged)
|
||||
{
|
||||
allGroupsExpanded = parameters.GetValueOrDefault<bool?>(nameof(AllGroupsExpanded));
|
||||
}
|
||||
|
||||
await base.SetParametersAsync(parameters);
|
||||
|
||||
if (valueChanged)
|
||||
@@ -1754,6 +1811,22 @@ namespace Radzen.Blazor
|
||||
}
|
||||
}
|
||||
|
||||
if (allowColumnPickingChanged || emptyTextChanged || allGroupsExpandedChanged && Groups.Any())
|
||||
{
|
||||
if (allGroupsExpandedChanged && Groups.Any() && allGroupsExpanded == true)
|
||||
{
|
||||
collapsedGroupItems.Clear();
|
||||
}
|
||||
|
||||
if (allowColumnPickingChanged)
|
||||
{
|
||||
selectedColumns = allColumns.Where(c => c.Pickable && c.GetVisible()).ToList();
|
||||
allPickableColumns = allColumns.Where(c => c.Pickable).ToList();
|
||||
}
|
||||
|
||||
await ChangeState();
|
||||
}
|
||||
|
||||
if (visibleChanged && !firstRender)
|
||||
{
|
||||
if (Visible == false)
|
||||
@@ -1812,6 +1885,61 @@ namespace Radzen.Blazor
|
||||
await ExpandItem(item);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Expands a range of rows.
|
||||
/// </summary>
|
||||
/// <param name="items">The range of rows.</param>
|
||||
public async System.Threading.Tasks.Task ExpandRows(IEnumerable<TItem> items)
|
||||
{
|
||||
// Only allow the functionality when multiple row expand is allowed
|
||||
if (this.ExpandMode != DataGridExpandMode.Multiple) return;
|
||||
|
||||
foreach (TItem item in items)
|
||||
{
|
||||
if (!expandedItems.Keys.Contains(item))
|
||||
{
|
||||
expandedItems.Add(item, true);
|
||||
await RowExpand.InvokeAsync(item);
|
||||
|
||||
var args = new DataGridLoadChildDataEventArgs<TItem>() { Item = item };
|
||||
await LoadChildData.InvokeAsync(args);
|
||||
|
||||
if (args.Data != null && !childData.ContainsKey(item))
|
||||
{
|
||||
childData.Add(item, new DataGridChildData<TItem>() { Data = args.Data, ParentChildData = childData.Where(c => c.Value.Data.Contains(item)).Select(c => c.Value).FirstOrDefault() });
|
||||
_view = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
await InvokeAsync(StateHasChanged);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Collapse a range of rows.
|
||||
/// </summary>
|
||||
/// <param name="items">The range of rows.</param>
|
||||
public async System.Threading.Tasks.Task CollapseRows(IEnumerable<TItem> items)
|
||||
{
|
||||
// Only allow the functionality when multiple row expand is allowed
|
||||
if (this.ExpandMode != DataGridExpandMode.Multiple) return;
|
||||
|
||||
foreach (TItem item in items)
|
||||
{
|
||||
if (expandedItems.Keys.Contains(item))
|
||||
{
|
||||
expandedItems.Remove(item);
|
||||
await RowCollapse.InvokeAsync(item);
|
||||
|
||||
if (childData.ContainsKey(item))
|
||||
{
|
||||
childData.Remove(item);
|
||||
_view = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
await InvokeAsync(StateHasChanged);
|
||||
}
|
||||
|
||||
internal async System.Threading.Tasks.Task ExpandItem(TItem item)
|
||||
{
|
||||
if (ExpandMode == DataGridExpandMode.Single && expandedItems.Keys.Any() && !LoadChildData.HasDelegate)
|
||||
@@ -1875,6 +2003,33 @@ namespace Radzen.Blazor
|
||||
[Parameter]
|
||||
public bool AllowAlternatingRows { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the grid lines.
|
||||
/// </summary>
|
||||
/// <value>The grid lines.</value>
|
||||
[Parameter]
|
||||
public DataGridGridLines GridLines { get; set; } = DataGridGridLines.Default;
|
||||
|
||||
internal bool ShowGridLines(RadzenDataGridColumn<TItem> column)
|
||||
{
|
||||
return column.Columns != null || column.Parent != null;
|
||||
}
|
||||
|
||||
internal string getCompositeCellCSSClass(RadzenDataGridColumn<TItem> column)
|
||||
{
|
||||
return column.Columns != null || column.Parent != null ? "rz-composite-cell" : "";
|
||||
}
|
||||
|
||||
internal string getGridLinesCSSClass()
|
||||
{
|
||||
if (GridLines == DataGridGridLines.Default)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
return $"rz-grid-gridlines-{Enum.GetName(typeof(DataGridGridLines), GridLines).ToLower()}";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the selection mode.
|
||||
/// </summary>
|
||||
@@ -1965,9 +2120,10 @@ namespace Radzen.Blazor
|
||||
/// Selects the row.
|
||||
/// </summary>
|
||||
/// <param name="item">The item.</param>
|
||||
public async System.Threading.Tasks.Task SelectRow(TItem item)
|
||||
/// <param name="raiseEvent">Should raise RowSelect event.</param>
|
||||
public async System.Threading.Tasks.Task SelectRow(TItem item, bool raiseEvent = true)
|
||||
{
|
||||
await OnRowSelect(item, true);
|
||||
await OnRowSelect(item, raiseEvent);
|
||||
}
|
||||
|
||||
internal async System.Threading.Tasks.Task OnRowDblClick(DataGridRowMouseEventArgs<TItem> args)
|
||||
@@ -2040,6 +2196,30 @@ namespace Radzen.Blazor
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Edits a range of rows.
|
||||
/// </summary>
|
||||
/// <param name="items">The range of rows.</param>
|
||||
public async System.Threading.Tasks.Task EditRows(IEnumerable<TItem> items)
|
||||
{
|
||||
// Only allow the functionality when multiple row edits is allowed
|
||||
if (this.EditMode != DataGridEditMode.Multiple) return;
|
||||
|
||||
foreach (TItem item in items)
|
||||
{
|
||||
if (!editedItems.Keys.Contains(item))
|
||||
{
|
||||
editedItems.Add(item, true);
|
||||
|
||||
var editContext = new EditContext(item);
|
||||
editContexts.Add(item, editContext);
|
||||
|
||||
await RowEdit.InvokeAsync(item);
|
||||
}
|
||||
}
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the row.
|
||||
/// </summary>
|
||||
@@ -2117,6 +2297,23 @@ namespace Radzen.Blazor
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Cancels the edit of a range of rows.
|
||||
/// </summary>
|
||||
/// <param name="items">The range of rows.</param>
|
||||
public void CancelEditRows(IEnumerable<TItem> items)
|
||||
{
|
||||
foreach (TItem item in items)
|
||||
{
|
||||
if (editedItems.Keys.Contains(item))
|
||||
{
|
||||
editedItems.Remove(item);
|
||||
editContexts.Remove(item);
|
||||
}
|
||||
}
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether row in edit mode.
|
||||
/// </summary>
|
||||
@@ -2289,8 +2486,11 @@ namespace Radzen.Blazor
|
||||
|
||||
internal async Task EndColumnDropToGroup()
|
||||
{
|
||||
if(indexOfColumnToReoder != null)
|
||||
if(indexOfColumnToReoder != null && AllowGrouping)
|
||||
{
|
||||
var functionName = $"Radzen['{getColumnResizerId(indexOfColumnToReoder.Value)}end']";
|
||||
await JSRuntime.InvokeVoidAsync("eval", $"{functionName} && {functionName}()");
|
||||
|
||||
var column = columns.Where(c => c.GetVisible()).ElementAtOrDefault(indexOfColumnToReoder.Value);
|
||||
|
||||
if(column != null && column.Groupable && !string.IsNullOrEmpty(column.GetGroupProperty()))
|
||||
@@ -2337,7 +2537,14 @@ namespace Radzen.Blazor
|
||||
Data = null;
|
||||
}
|
||||
|
||||
InvokeAsync(Reload);
|
||||
if (IsVirtualizationAllowed() && LoadData.HasDelegate)
|
||||
{
|
||||
Debounce(() => InvokeAsync(Reload), 500);
|
||||
}
|
||||
else
|
||||
{
|
||||
InvokeAsync(Reload);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -2475,6 +2682,7 @@ namespace Radzen.Blazor
|
||||
FilterOperator = c.GetFilterOperator(),
|
||||
SecondFilterValue = c.GetSecondFilterValue(),
|
||||
SecondFilterOperator = c.GetSecondFilterOperator(),
|
||||
LogicalFilterOperator = c.GetLogicalFilterOperator()
|
||||
}).ToList(),
|
||||
CurrentPage = CurrentPage,
|
||||
PageSize = PageSize,
|
||||
@@ -2493,6 +2701,12 @@ namespace Radzen.Blazor
|
||||
if (SettingsChanged.HasDelegate)
|
||||
{
|
||||
var shouldUpdateState = false;
|
||||
var hasFilter = settings.Columns != null && settings.Columns.Any(c =>
|
||||
c.FilterValue != null || c.SecondFilterValue != null ||
|
||||
c.FilterOperator == FilterOperator.IsNull || c.FilterOperator == FilterOperator.IsNotNull ||
|
||||
c.FilterOperator == FilterOperator.IsEmpty || c.FilterOperator == FilterOperator.IsNotEmpty ||
|
||||
c.SecondFilterOperator == FilterOperator.IsNull || c.SecondFilterOperator == FilterOperator.IsNotNull ||
|
||||
c.SecondFilterOperator == FilterOperator.IsEmpty || c.SecondFilterOperator == FilterOperator.IsNotEmpty);
|
||||
|
||||
if (settings.Columns != null)
|
||||
{
|
||||
@@ -2547,6 +2761,18 @@ namespace Radzen.Blazor
|
||||
gridColumn.SetFilterValue(GetFilterValue(column.SecondFilterValue, gridColumn.FilterPropertyType), false);
|
||||
shouldUpdateState = true;
|
||||
}
|
||||
|
||||
if (gridColumn.GetSecondFilterOperator() != column.SecondFilterOperator)
|
||||
{
|
||||
gridColumn.SetSecondFilterOperator(column.SecondFilterOperator);
|
||||
shouldUpdateState = true;
|
||||
}
|
||||
|
||||
if (gridColumn.GetLogicalFilterOperator() != column.LogicalFilterOperator)
|
||||
{
|
||||
gridColumn.SetLogicalFilterOperator(column.LogicalFilterOperator);
|
||||
shouldUpdateState = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2575,9 +2801,13 @@ namespace Radzen.Blazor
|
||||
if (shouldUpdateState)
|
||||
{
|
||||
skip = CurrentPage * PageSize;
|
||||
CalculatePager();
|
||||
UpdateColumnsOrder();
|
||||
await Reload();
|
||||
|
||||
if (hasFilter ? skip < View.Count() : true)
|
||||
{
|
||||
CalculatePager();
|
||||
UpdateColumnsOrder();
|
||||
await Reload();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2673,6 +2903,7 @@ namespace Radzen.Blazor
|
||||
{
|
||||
c.SetVisible(true);
|
||||
});
|
||||
columns = allColumns.Where(c => c.Parent == null).ToList();
|
||||
InvokeAsync(Reload);
|
||||
|
||||
canSaveSettings = true;
|
||||
|
||||
@@ -15,7 +15,7 @@ else
|
||||
@foreach(var column in Grid.childColumns.Where(c => c.GetVisible() && c.Parent == Column))
|
||||
{
|
||||
<RadzenDataGridCell Row=@Row EditContext=EditContext RowIndex="@RowIndex" Grid="@Grid" Column="@column" Item="@Item"
|
||||
Style="@column.GetStyle(true)" CssClass="@(column.CssClass + " " + Grid.getFrozenColumnClass(column, Grid.ColumnsCollection) + " " + (column.Columns != null || column.Parent != null ? "rz-composite-cell" : ""))" Attributes="@(Grid.CellAttributes(Item, column))">
|
||||
Style="@column.GetStyle(true)" CssClass="@(column.CssClass + " " + Grid.getFrozenColumnClass(column, Grid.ColumnsCollection) + " " + Grid.getCompositeCellCSSClass(column))" Attributes="@(Grid.CellAttributes(Item, column))">
|
||||
@if (Grid.Responsive)
|
||||
{
|
||||
<span class="rz-column-title">
|
||||
@@ -29,7 +29,7 @@ else
|
||||
}
|
||||
</span>
|
||||
}
|
||||
<span class="rz-cell-data" title="@(column.Template == null ? column.GetValue(Item) : "")">
|
||||
<span class="rz-cell-data" title="@(column.Template == null && Grid.ShowCellDataAsTooltip ? column.GetValue(Item) : "")">
|
||||
@if (Item != null)
|
||||
{
|
||||
@if (Grid.IsRowInEditMode(Item) && column.EditTemplate != null)
|
||||
|
||||
@@ -196,6 +196,11 @@ namespace Radzen.Blazor
|
||||
|
||||
if (Grid != null)
|
||||
{
|
||||
if (value == false)
|
||||
{
|
||||
Grid.GetJSRuntime().InvokeVoidAsync("Radzen.destroyPopup", $"{Grid.PopupID}{GetFilterProperty()}");
|
||||
}
|
||||
|
||||
Grid.UpdatePickableColumn(this, _visible == true);
|
||||
}
|
||||
}
|
||||
@@ -421,7 +426,16 @@ namespace Radzen.Blazor
|
||||
{
|
||||
var value = propertyValueGetter != null && !string.IsNullOrEmpty(Property) && !Property.Contains('.') ? propertyValueGetter(item) : !string.IsNullOrEmpty(Property) ? PropertyAccess.GetValue(item, Property) : "";
|
||||
|
||||
return !string.IsNullOrEmpty(FormatString) ? string.Format(FormatString, value, Grid?.Culture ?? CultureInfo.CurrentCulture) : Convert.ToString(value, Grid?.Culture ?? CultureInfo.CurrentCulture);
|
||||
if ((PropertyAccess.IsEnum(FilterPropertyType) || PropertyAccess.IsNullableEnum(FilterPropertyType)) && value != null)
|
||||
{
|
||||
var enumValue = value as Enum;
|
||||
if (enumValue != null)
|
||||
{
|
||||
value = EnumExtensions.GetDisplayDescription(enumValue);
|
||||
}
|
||||
}
|
||||
|
||||
return !string.IsNullOrEmpty(FormatString) ? string.Format(Grid?.Culture ?? CultureInfo.CurrentCulture, FormatString, value) : Convert.ToString(value, Grid?.Culture ?? CultureInfo.CurrentCulture);
|
||||
}
|
||||
|
||||
internal object GetHeader()
|
||||
|
||||
@@ -144,6 +144,8 @@
|
||||
|
||||
Column.SetFilterOperator(value);
|
||||
|
||||
Grid.SaveSettings();
|
||||
|
||||
await Grid.Filter.InvokeAsync(new DataGridColumnFilterEventArgs<TItem>()
|
||||
{
|
||||
Column = Column,
|
||||
|
||||
@@ -15,7 +15,7 @@ else
|
||||
@foreach(var column in Grid.childColumns.Where(c => c.GetVisible() && c.Parent == Column))
|
||||
{
|
||||
<RadzenDataGridFooterCell RowIndex="@RowIndex" Grid="@Grid" Column="@column"
|
||||
CssClass="@($"{Column.FooterCssClass} {Grid.getFrozenColumnClass(column, Grid.ColumnsCollection.Where(c => c.GetVisible()).ToList())} {(column.Columns != null || column.Parent != null ? "rz-composite-cell" : "")}")"
|
||||
CssClass="@($"{Column.FooterCssClass} {Grid.getFrozenColumnClass(column, Grid.ColumnsCollection.Where(c => c.GetVisible()).ToList())} {Grid.getCompositeCellCSSClass(column)}")"
|
||||
Attributes="@(Attributes)" />
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
@{
|
||||
var rowArgs = Grid?.GroupRowAttributes(this);
|
||||
}
|
||||
<tr @attributes="@rowArgs.Item2">
|
||||
<tr class="rz-group-row" @attributes="@rowArgs.Item2">
|
||||
@if (Group.GroupDescriptor != null)
|
||||
{
|
||||
@for (var i = 0; i < GetLevel(); i++)
|
||||
@@ -17,7 +17,7 @@
|
||||
<td class="rz-col-icon">
|
||||
<span class="rz-column-title"></span>
|
||||
<a href="javascript:void(0)" @onclick="@(_ => Grid.ExpandGroupItem(this, rowArgs.Item1.Expanded))">
|
||||
<span class="@(Grid.ExpandedGroupItemStyle(this, rowArgs.Item1.Expanded))"></span>
|
||||
<span class="@(Grid.ExpandedGroupItemStyle(this, Grid.allGroupsExpanded != null ? Grid.allGroupsExpanded : rowArgs.Item1.Expanded))"></span>
|
||||
</a>
|
||||
</td>
|
||||
<td colspan="@(Columns.Count + Grid.Groups.Count - 1 - Group.Level + (Grid.Template != null && Grid.ShowExpandColumn ? 1 : 0))">
|
||||
@@ -28,14 +28,14 @@
|
||||
}
|
||||
else if(Group.GroupDescriptor != null)
|
||||
{
|
||||
@(Group.GroupDescriptor.GetTitle() + ": " + (Group.Data.Key ?? ""))
|
||||
@(Group.GroupDescriptor.GetTitle() + ": " + (Group.Data.Key != null ? Group.Data.Key.ToString() : ""))
|
||||
}
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
@if(Grid != null)
|
||||
{
|
||||
if (Grid.IsGroupItemExpanded(this) && rowArgs.Item1.Expanded != false)
|
||||
if (Grid.IsGroupItemExpanded(this) && rowArgs.Item1.Expanded != false && Grid.allGroupsExpanded != false)
|
||||
{
|
||||
@DrawDataRows()
|
||||
}
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
@typeparam TItem
|
||||
@using Radzen.Blazor.Rendering
|
||||
@if (RowIndex == Column.GetLevel())
|
||||
{
|
||||
<th rowspan="@(Column.GetRowSpan())" colspan="@(Column.GetColSpan())" @attributes="@Attributes" class="@CssClass" scope="col" style="@Column.GetStyle(true, true)" @onmouseup=@(args => Grid.EndColumnReorder(args, ColumnIndex)) >
|
||||
<div @onclick='@((args) => Grid.OnSort(args, Column))' tabindex="@SortingTabIndex" @onkeydown="OnSortKeyPressed">
|
||||
@if (Column.Parent == null && Column.Columns == null && (Grid.AllowColumnReorder && Column.Reorderable || Grid.AllowGrouping && Column.Groupable))
|
||||
{
|
||||
<span id="@Grid.getColumnResizerId(ColumnIndex)" class="rz-column-drag"
|
||||
<span id="@Grid.getColumnResizerId(ColumnIndex)" class="rz-column-drag"
|
||||
@onclick:preventDefault="true" @onclick:stopPropagation="true"
|
||||
@onmousedown:preventDefault="true"
|
||||
@onmousedown=@(args => Grid.StartColumnReorder(args, ColumnIndex))></span>
|
||||
}
|
||||
<span class="rz-column-title" title="@Column.Title">
|
||||
@@ -18,7 +20,7 @@
|
||||
{
|
||||
<span class="rz-column-title-content">@Column.Title</span>
|
||||
}
|
||||
|
||||
|
||||
@if (Grid.AllowSorting && Column.Sortable)
|
||||
{
|
||||
@if (Column.GetSortOrder() == SortOrder.Ascending)
|
||||
@@ -46,23 +48,25 @@
|
||||
@if (Grid.AllowColumnResize && Column.Resizable && Column.Parent == null)
|
||||
{
|
||||
<div id="@Grid.getColumnResizerId(ColumnIndex)" style="cursor:col-resize;float:right;"
|
||||
@onclick:preventDefault="true" @onclick:stopPropagation="true" class="rz-column-resizer"
|
||||
@onclick:preventDefault="true" @onclick:stopPropagation="true" class="rz-column-resizer"
|
||||
@onmousedown:preventDefault="true"
|
||||
@onmousedown=@(args => Grid.StartColumnResize(args, ColumnIndex))> </div>
|
||||
}
|
||||
@if (Grid.AllowFiltering && Column.Filterable && Grid.FilterMode == FilterMode.Advanced)
|
||||
{
|
||||
<i @onclick:stopPropagation="true" onclick="@($"Radzen.togglePopup(this, '{getColumnPopupID()}')")"
|
||||
class="@getFilterIconCss(Column)" />
|
||||
<i @ref=@filterButton @onclick:stopPropagation="true" @onmousedown=@ToggleFilter
|
||||
class="@getFilterIconCss(Column)" onclick=@getFilterOpen() />
|
||||
|
||||
<div id="@($"{getColumnPopupID()}")" class="rz-overlaypanel"
|
||||
<Popup Lazy=@(Grid.FilterPopupRenderMode == PopupRenderMode.OnDemand) @ref=popup id="@($"{getColumnPopupID()}")" class="rz-overlaypanel"
|
||||
style="display:none;min-width:250px;" tabindex="0">
|
||||
<div class="rz-grid-filter rz-overlaypanel-content">
|
||||
<div class="rz-overlaypanel-content">
|
||||
@if (Column.FilterTemplate != null)
|
||||
{
|
||||
@Column.FilterTemplate(Column)
|
||||
}
|
||||
else
|
||||
{
|
||||
<form id="@($"{getColumnPopupID()}-form")" @onsubmit="@(args => ApplyFilter())" class="rz-grid-filter">
|
||||
<RadzenLabel Text="@Grid.FilterText" class="rz-grid-filter-label" />
|
||||
<RadzenDropDown @onclick:preventDefault="true" Data="@(Column.GetFilterOperators().Select(t => new { Value = Column.GetFilterOperatorText(t), Key = t }))" TextProperty="Value" ValueProperty="Key" TValue="FilterOperator" Value="@Column.GetFilterOperator()" Change="@(args => Column.SetFilterOperator((FilterOperator)args))" />
|
||||
@if (PropertyAccess.IsNullableEnum(Column.FilterPropertyType) || PropertyAccess.IsEnum(Column.FilterPropertyType))
|
||||
@@ -113,22 +117,23 @@
|
||||
}
|
||||
else if (Column.FilterPropertyType == typeof(bool) || Column.FilterPropertyType == typeof(bool?))
|
||||
{
|
||||
<RadzenCheckBox TriState="true" TValue="@object" Value="@Column.GetSecondFilterValue()" Change="@(args => { Column.SetFilterValue(args, false); Grid.SaveSettings(); })" />
|
||||
<RadzenCheckBox TriState="true" TValue="@object" Value="@Column.GetSecondFilterValue()" Change="@(args => { Column.SetFilterValue(args, false); Grid.SaveSettings(); })" />
|
||||
}
|
||||
else
|
||||
{
|
||||
<RadzenTextBox Value="@($"{Column.GetSecondFilterValue()}")" Change="@(args => Column.SetFilterValue(args, false))" />
|
||||
}
|
||||
</form>
|
||||
}
|
||||
</div>
|
||||
@if (Column.FilterTemplate == null)
|
||||
{
|
||||
<div class="rz-grid-filter-buttons">
|
||||
<RadzenButton ButtonStyle="ButtonStyle.Secondary" Text=@Grid.ClearFilterText Click="@((args) => Grid.ClearFilter(Column, true))" />
|
||||
<RadzenButton ButtonStyle="ButtonStyle.Primary" Text=@Grid.ApplyFilterText Click="@((args) => Grid.ApplyFilter(Column, true))" />
|
||||
<RadzenButton ButtonStyle="ButtonStyle.Secondary" Text=@Grid.ClearFilterText Click="@ClearFilter" />
|
||||
<RadzenButton form="@($"{getColumnPopupID()}-form")" ButtonType="ButtonType.Submit" ButtonStyle="ButtonStyle.Primary" Text=@Grid.ApplyFilterText Click="@ApplyFilter" />
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</Popup>
|
||||
}
|
||||
</div>
|
||||
</th>
|
||||
@@ -137,11 +142,45 @@ else
|
||||
{
|
||||
@foreach(var column in Grid.childColumns.Where(c => c.GetVisible() && c.Parent == Column))
|
||||
{
|
||||
<RadzenDataGridHeaderCell RowIndex="@RowIndex" Grid="@Grid" Column="@column" ColumnIndex="@ColumnIndex"
|
||||
CssClass="@($"rz-unselectable-text {(Grid.AllowSorting && column.Sortable ? "rz-sortable-column" : "")} {column.HeaderCssClass} {Grid.getFrozenColumnClass(column, Grid.ColumnsCollection.Where(c => c.GetVisible()).ToList())} {(column.Columns != null || column.Parent != null ? "rz-composite-cell" : "")} {Grid.getColumnAlignClass(column)}".Trim())" />
|
||||
<RadzenDataGridHeaderCell RowIndex="@RowIndex" Grid="@Grid" Column="@column" ColumnIndex="@ColumnIndex"
|
||||
CssClass="@($"rz-unselectable-text {(Grid.AllowSorting && column.Sortable ? "rz-sortable-column" : "")} {column.HeaderCssClass} {Grid.getFrozenColumnClass(column, Grid.ColumnsCollection.Where(c => c.GetVisible()).ToList())} {Grid.getCompositeCellCSSClass(column)} {Grid.getColumnAlignClass(column)}".Trim())" />
|
||||
}
|
||||
}
|
||||
@code {
|
||||
Radzen.Blazor.Rendering.Popup popup;
|
||||
ElementReference filterButton;
|
||||
|
||||
string getFilterOpen()
|
||||
{
|
||||
return Grid.FilterPopupRenderMode == PopupRenderMode.Initial ? $"Radzen.togglePopup(this, '{getColumnPopupID()}')" : "";
|
||||
}
|
||||
|
||||
async Task ToggleFilter()
|
||||
{
|
||||
if (Grid.FilterPopupRenderMode == PopupRenderMode.OnDemand)
|
||||
{
|
||||
await popup.ToggleAsync(filterButton);
|
||||
}
|
||||
}
|
||||
|
||||
async Task ClearFilter()
|
||||
{
|
||||
if (Grid.FilterPopupRenderMode == PopupRenderMode.OnDemand)
|
||||
{
|
||||
await popup.CloseAsync();
|
||||
}
|
||||
await Grid.ClearFilter(Column, true);
|
||||
}
|
||||
|
||||
async Task ApplyFilter()
|
||||
{
|
||||
if (Grid.FilterPopupRenderMode == PopupRenderMode.OnDemand)
|
||||
{
|
||||
await popup.CloseAsync();
|
||||
}
|
||||
await Grid.ApplyFilter(Column, true);
|
||||
}
|
||||
|
||||
[Parameter(CaptureUnmatchedValues = true)]
|
||||
public IReadOnlyDictionary<string, object> Attributes { get; set; }
|
||||
|
||||
@@ -164,8 +203,8 @@ else
|
||||
|
||||
private string getFilterIconCss(RadzenDataGridColumn<TItem> column)
|
||||
{
|
||||
var additionalStyle = column.GetFilterValue() != null || column.GetSecondFilterValue() != null ||
|
||||
column.GetFilterOperator() == FilterOperator.IsNotNull || column.GetFilterOperator() == FilterOperator.IsNull
|
||||
var additionalStyle = column.GetFilterValue() != null || column.GetSecondFilterValue() != null ||
|
||||
column.GetFilterOperator() == FilterOperator.IsNotNull || column.GetFilterOperator() == FilterOperator.IsNull
|
||||
|| column.GetFilterOperator() == FilterOperator.IsEmpty || column.GetFilterOperator() == FilterOperator.IsNotEmpty
|
||||
? "rz-grid-filter-active" : "";
|
||||
return $"rzi rz-grid-filter-icon {additionalStyle}";
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
<span class="rz-column-title"></span>
|
||||
@if (rowArgs.Item1.Expandable)
|
||||
{
|
||||
<a href="javascript:void(0)" @onclick="@(_ => Grid.ExpandItem(Item))">
|
||||
<a href="javascript:void(0)" @onclick="@(_ => Grid.ExpandItem(Item))" @onclick:stopPropagation>
|
||||
<span class="@(Grid.ExpandedItemStyle(Item))"></span>
|
||||
</a>
|
||||
}
|
||||
@@ -61,7 +61,7 @@
|
||||
}
|
||||
|
||||
<RadzenDataGridCell Row=@this EditContext=EditContext RowIndex="@i" Grid="@this.Grid" Item="@Item" Column="@column"
|
||||
Style="@column.GetStyle(true)" CssClass="@(column.CssClass + " " + Grid.getFrozenColumnClass(column, Columns) + " " + (column.Columns != null || column.Parent != null ? "rz-composite-cell" : ""))" Attributes="@(cellAttr)">
|
||||
Style="@column.GetStyle(true)" CssClass="@(column.CssClass + " " + Grid.getFrozenColumnClass(column, Columns) + " " + Grid.getCompositeCellCSSClass(column))" Attributes="@(cellAttr)">
|
||||
@if (Grid.Responsive)
|
||||
{
|
||||
<span class="rz-column-title">
|
||||
@@ -78,7 +78,7 @@
|
||||
@if (Grid.LoadChildData.HasDelegate && Grid.ShowExpandColumn && Grid.allColumns.IndexOf(column) == 0)
|
||||
{
|
||||
<span class="rz-cell-toggle">
|
||||
<a style="@(getExpandIconStyle(rowArgs.Item1.Expandable))" href="javascript:void(0)" @onclick="@(_ => Grid.ExpandItem(Item))">
|
||||
<a style="@(getExpandIconStyle(rowArgs.Item1.Expandable))" href="javascript:void(0)" @onclick="@(_ => Grid.ExpandItem(Item))" @onclick:stopPropagation>
|
||||
<span class="@(Grid.ExpandedItemStyle(Item))"></span>
|
||||
</a>
|
||||
<span class="rz-cell-data" title="@(column.Template == null ? column.GetValue(Item) : "")">
|
||||
@@ -129,7 +129,7 @@
|
||||
@if (Grid.Template != null && Grid.expandedItems.Keys.Contains(Item))
|
||||
{
|
||||
<tr class="rz-expanded-row-content">
|
||||
<td colspan="@(Columns.Count + (Grid.ShowExpandColumn ? 1 : 0) + + Grid.Groups.Count)">
|
||||
<td colspan="@(Columns.Sum(c => c.GetColSpan()) + (Grid.ShowExpandColumn ? 1 : 0) + Grid.Groups.Count)">
|
||||
<div class="rz-expanded-row-template" style="position:sticky">
|
||||
@Grid.Template(Item)
|
||||
</div>
|
||||
|
||||
@@ -12,36 +12,12 @@
|
||||
{
|
||||
@if (!WrapItems)
|
||||
{
|
||||
@foreach (var item in LoadData.HasDelegate ? Data : PagedView)
|
||||
{
|
||||
<ul class="rz-datalist-data">
|
||||
<li>
|
||||
@if (Template != null)
|
||||
{
|
||||
@Template(item)
|
||||
}
|
||||
else
|
||||
{
|
||||
<span>Template</span>
|
||||
}
|
||||
</li>
|
||||
</ul>
|
||||
}
|
||||
@DrawDataListRows()
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="rz-g">
|
||||
@foreach (var item in LoadData.HasDelegate ? Data : PagedView)
|
||||
{
|
||||
@if (Template != null)
|
||||
{
|
||||
@Template(item)
|
||||
}
|
||||
else
|
||||
{
|
||||
<span>Template</span>
|
||||
}
|
||||
}
|
||||
@DrawDataListRows()
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,16 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.AspNetCore.Components.Forms;
|
||||
using Microsoft.AspNetCore.Components.Web;
|
||||
using Microsoft.JSInterop;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Collections.Specialized;
|
||||
using System.Data.Common;
|
||||
using System.Linq;
|
||||
using System.Linq.Dynamic.Core;
|
||||
using System.Text.Json;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Radzen.Blazor
|
||||
{
|
||||
@@ -29,5 +41,98 @@ namespace Radzen.Blazor
|
||||
/// <value><c>true</c> if wrap items; otherwise, <c>false</c>.</value>
|
||||
[Parameter]
|
||||
public bool WrapItems { get; set; }
|
||||
#if NET5_0_OR_GREATER
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether this instance is virtualized.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if this instance is virtualized; otherwise, <c>false</c>.</value>
|
||||
[Parameter]
|
||||
public bool AllowVirtualization { get; set; }
|
||||
|
||||
internal Microsoft.AspNetCore.Components.Web.Virtualization.Virtualize<TItem> virtualize;
|
||||
|
||||
/// <summary>
|
||||
/// Gets Virtualize component reference.
|
||||
/// </summary>
|
||||
public Microsoft.AspNetCore.Components.Web.Virtualization.Virtualize<TItem> Virtualize
|
||||
{
|
||||
get
|
||||
{
|
||||
return virtualize;
|
||||
}
|
||||
}
|
||||
|
||||
private async ValueTask<Microsoft.AspNetCore.Components.Web.Virtualization.ItemsProviderResult<TItem>> LoadItems(Microsoft.AspNetCore.Components.Web.Virtualization.ItemsProviderRequest request)
|
||||
{
|
||||
var view = AllowPaging ? PagedView : View;
|
||||
var top = request.Count;
|
||||
|
||||
if(top <= 0)
|
||||
{
|
||||
top = PageSize;
|
||||
}
|
||||
|
||||
await LoadData.InvokeAsync(new Radzen.LoadDataArgs()
|
||||
{
|
||||
Skip = request.StartIndex,
|
||||
Top = top
|
||||
});
|
||||
|
||||
var totalItemsCount = LoadData.HasDelegate ? Count : view.Count();
|
||||
|
||||
var virtualDataItems = (LoadData.HasDelegate ? Data : view.Skip(request.StartIndex).Take(top))?.ToList();
|
||||
|
||||
return new Microsoft.AspNetCore.Components.Web.Virtualization.ItemsProviderResult<TItem>(virtualDataItems, totalItemsCount);
|
||||
}
|
||||
#endif
|
||||
RenderFragment DrawDataListRows()
|
||||
{
|
||||
return new RenderFragment(builder =>
|
||||
{
|
||||
#if NET5_0_OR_GREATER
|
||||
if (AllowVirtualization)
|
||||
{
|
||||
builder.OpenComponent(0, typeof(Microsoft.AspNetCore.Components.Web.Virtualization.Virtualize<TItem>));
|
||||
builder.AddAttribute(1, "ItemsProvider", new Microsoft.AspNetCore.Components.Web.Virtualization.ItemsProviderDelegate<TItem>(LoadItems));
|
||||
|
||||
builder.AddAttribute(2, "ChildContent", (RenderFragment<TItem>)((context) =>
|
||||
{
|
||||
return (RenderFragment)((b) =>
|
||||
{
|
||||
DrawRow(b, context);
|
||||
});
|
||||
}));
|
||||
|
||||
builder.AddComponentReferenceCapture(4, c => { virtualize = (Microsoft.AspNetCore.Components.Web.Virtualization.Virtualize<TItem>)c; });
|
||||
|
||||
builder.CloseComponent();
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawRows(builder);
|
||||
}
|
||||
#else
|
||||
DrawRows(builder);
|
||||
#endif
|
||||
});
|
||||
}
|
||||
|
||||
internal void DrawRows(Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder builder)
|
||||
{
|
||||
foreach (var item in LoadData.HasDelegate ? Data : PagedView)
|
||||
{
|
||||
DrawRow(builder, item);
|
||||
}
|
||||
}
|
||||
|
||||
internal void DrawRow(Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder builder, TItem item)
|
||||
{
|
||||
builder.OpenComponent<RadzenDataListRow<TItem>>(0);
|
||||
builder.AddAttribute(1, "DataList", this);
|
||||
builder.AddAttribute(2, "Item", item);
|
||||
builder.SetKey(item);
|
||||
builder.CloseComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
36
Radzen.Blazor/RadzenDataListRow.razor
Normal file
36
Radzen.Blazor/RadzenDataListRow.razor
Normal file
@@ -0,0 +1,36 @@
|
||||
@typeparam TItem
|
||||
|
||||
@if (!DataList.WrapItems)
|
||||
{
|
||||
<ul class="rz-datalist-data">
|
||||
<li>
|
||||
@if (DataList.Template != null)
|
||||
{
|
||||
@DataList.Template(Item)
|
||||
}
|
||||
else
|
||||
{
|
||||
<span>Template</span>
|
||||
}
|
||||
</li>
|
||||
</ul>
|
||||
}
|
||||
else
|
||||
{
|
||||
@if (DataList.Template != null)
|
||||
{
|
||||
@DataList.Template(Item)
|
||||
}
|
||||
else
|
||||
{
|
||||
<span>Template</span>
|
||||
}
|
||||
}
|
||||
|
||||
@code {
|
||||
[Parameter]
|
||||
public RadzenDataList<TItem> DataList { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public TItem Item { get; set; }
|
||||
}
|
||||
@@ -564,6 +564,9 @@ namespace Radzen.Blazor
|
||||
|
||||
async Task Clear()
|
||||
{
|
||||
if (Disabled || ReadOnly)
|
||||
return;
|
||||
|
||||
Value = null;
|
||||
|
||||
await ValueChanged.InvokeAsync(default(TValue));
|
||||
|
||||
@@ -8,19 +8,57 @@
|
||||
<DialogContainer Dialog=@dialog ShowMask=@(dialog==dialogs.LastOrDefault()) />
|
||||
}
|
||||
|
||||
@if (isSideDialogOpen)
|
||||
{
|
||||
<aside
|
||||
class="@GetSideDialogCssClass()"
|
||||
tabindex="@(isSideDialogOpen ? "0" : "-1")"
|
||||
style="@GetSideDialogStyle()"
|
||||
aria-labelledby="rz-dialog-side-label"
|
||||
>
|
||||
@if (sideDialogOptions.ShowTitle)
|
||||
{
|
||||
<div class="rz-dialog-side-titlebar">
|
||||
<div class="rz-dialog-side-title" style="display: inline" id="rz-dialog-side-label">@((MarkupString)sideDialogOptions.Title)</div>
|
||||
@if (sideDialogOptions.ShowClose)
|
||||
{
|
||||
<a href="javascript:void(0)" class="rz-dialog-side-titlebar-close" @onclick="@(_ => Service.CloseSide(null))" role="button">
|
||||
<span class="rzi rzi-times"></span>
|
||||
</a>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
<div class="rz-dialog-side-content" style="@sideDialogOptions.Style">
|
||||
@sideDialogContent
|
||||
</div>
|
||||
</aside>
|
||||
@if (dialogs.Count == 0 && sideDialogOptions.ShowMask)
|
||||
{
|
||||
@if (sideDialogOptions.CloseDialogOnOverlayClick)
|
||||
{
|
||||
<div @onclick="@Service.CloseSide" class="rz-dialog-mask"></div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="rz-dialog-mask"></div>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@code {
|
||||
[Inject]
|
||||
DialogService Service { get; set; }
|
||||
|
||||
List<Dialog> dialogs = new List<Dialog>();
|
||||
bool isSideDialogOpen = false;
|
||||
RenderFragment sideDialogContent;
|
||||
SideDialogOptions sideDialogOptions;
|
||||
|
||||
public async Task Open(string title, Type type, Dictionary<string, object> parameters, DialogOptions options)
|
||||
{
|
||||
dialogs.Add(new Dialog() { Title = title, Type = type, Parameters = parameters, Options = options });
|
||||
|
||||
await InvokeAsync(() => { StateHasChanged(); });
|
||||
|
||||
await JSRuntime.InvokeAsync<string>("Radzen.openDialog", options, Service.Reference);
|
||||
}
|
||||
|
||||
public async Task Close(dynamic result)
|
||||
@@ -42,12 +80,40 @@
|
||||
{
|
||||
Service.OnOpen -= OnOpen;
|
||||
Service.OnClose -= OnClose;
|
||||
|
||||
Service.OnSideOpen -= OnSideOpen;
|
||||
Service.OnSideClose -= OnSideClose;
|
||||
}
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
Service.OnOpen += OnOpen;
|
||||
Service.OnClose += OnClose;
|
||||
|
||||
Service.OnSideOpen += OnSideOpen;
|
||||
Service.OnSideClose += OnSideClose;
|
||||
}
|
||||
|
||||
void OnSideOpen(Type sideComponent, Dictionary<string, object> parameters, SideDialogOptions options)
|
||||
{
|
||||
sideDialogOptions = options;
|
||||
sideDialogContent = new RenderFragment(builder =>
|
||||
{
|
||||
builder.OpenComponent(0, sideComponent);
|
||||
foreach (var parameter in parameters)
|
||||
{
|
||||
builder.AddAttribute(1, parameter.Key, parameter.Value);
|
||||
}
|
||||
builder.CloseComponent();
|
||||
});
|
||||
isSideDialogOpen = true;
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
void OnSideClose(dynamic _)
|
||||
{
|
||||
isSideDialogOpen = false;
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
void OnOpen(string title, Type type, Dictionary<string, object> parameters, DialogOptions options)
|
||||
@@ -59,4 +125,14 @@
|
||||
{
|
||||
Close(result).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
string GetSideDialogCssClass()
|
||||
{
|
||||
return $"rz-dialog-side rz-dialog-side-position-{sideDialogOptions.Position.ToString().ToLower()} {sideDialogOptions.CssClass}";
|
||||
}
|
||||
|
||||
string GetSideDialogStyle()
|
||||
{
|
||||
return $"{sideDialogOptions.Style}{(sideDialogOptions.Width != null ? $" width: {sideDialogOptions.Width}" : "")}{(sideDialogOptions.Height != null ? $" height: {sideDialogOptions.Height}" : "")}";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,9 +42,16 @@
|
||||
{
|
||||
<div class="rz-chip">
|
||||
<span class="rz-chip-text">
|
||||
@GetItemOrValueFromProperty(item, TextProperty)
|
||||
</span>
|
||||
<button class="rz-button rz-button-sm rz-button-icon-only rz-light @(Disabled ?"rz-state-disabled":"")" @onclick:preventDefault @onclick:stopPropagation @onclick="() => OnChipRemove(item)"><RadzenIcon Icon="close" /></button>
|
||||
@if(Template != null)
|
||||
{
|
||||
@Template(item)
|
||||
}
|
||||
else
|
||||
{
|
||||
@GetItemOrValueFromProperty(item, TextProperty)
|
||||
}
|
||||
</span>
|
||||
<button type=button class="rz-button rz-button-sm rz-button-icon-only rz-light @(Disabled ?"rz-state-disabled":"")" @onclick:preventDefault @onclick:stopPropagation @onclick="() => OnChipRemove(item)"><RadzenIcon Icon="close" /></button>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
@@ -38,6 +38,13 @@ namespace Radzen.Blazor
|
||||
/// <value><c>true</c> if popup should open on focus; otherwise, <c>false</c>.</value>
|
||||
[Parameter]
|
||||
public bool OpenOnFocus { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether search field need to be cleared after selection. Set to <c>false</c> by default.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if need to be cleared; otherwise, <c>false</c>.</value>
|
||||
[Parameter]
|
||||
public bool ClearSearchAfterSelection { get; set; }
|
||||
|
||||
private async Task OnFocus(Microsoft.AspNetCore.Components.Web.FocusEventArgs args)
|
||||
{
|
||||
@@ -195,6 +202,12 @@ namespace Radzen.Blazor
|
||||
{
|
||||
await JSRuntime.InvokeVoidAsync("Radzen.closePopup", PopupID);
|
||||
}
|
||||
|
||||
if (ClearSearchAfterSelection)
|
||||
{
|
||||
await JSRuntime.InvokeAsync<string>("Radzen.setInputValue", search, string.Empty);
|
||||
await OnFilter(null);
|
||||
}
|
||||
|
||||
await SelectItem(item);
|
||||
}
|
||||
|
||||
@@ -46,9 +46,16 @@
|
||||
{
|
||||
<div class="rz-chip">
|
||||
<span class="rz-chip-text">
|
||||
@PropertyAccess.GetItemOrValueFromProperty(item, TextProperty)
|
||||
@if (Template != null)
|
||||
{
|
||||
@Template(item)
|
||||
}
|
||||
else
|
||||
{
|
||||
@PropertyAccess.GetItemOrValueFromProperty(item, TextProperty)
|
||||
}
|
||||
</span>
|
||||
<button class="rz-button rz-button-sm rz-button-icon-only rz-light @(Disabled ?"rz-state-disabled":"")" @onclick:preventDefault @onclick:stopPropagation @onclick="() => OnChipRemove(item)"><RadzenIcon Icon="close" /></button>
|
||||
<button type="button" class="rz-button rz-button-sm rz-button-icon-only rz-light @(Disabled ?"rz-state-disabled":"")" @onclick:preventDefault @onclick:stopPropagation @onclick="() => OnChipRemove(item)"><RadzenIcon Icon="close" /></button>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
@@ -60,13 +67,13 @@
|
||||
{
|
||||
@if (Template == null)
|
||||
{
|
||||
@(string.Join(",", itemsToUse.Select(i => PropertyAccess.GetItemOrValueFromProperty(i, TextProperty))))
|
||||
@(string.Join(Separator, itemsToUse.Select(i => PropertyAccess.GetItemOrValueFromProperty(i, TextProperty))))
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var item in itemsToUse)
|
||||
{
|
||||
@Template(item)@(",")
|
||||
@Template(item)@(Separator)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -106,7 +113,7 @@
|
||||
@if (AllowFiltering)
|
||||
{
|
||||
<div class="rz-lookup-search">
|
||||
<input id="@SearchID" @ref="@search" tabindex="-1" placeholder="@SearchText"
|
||||
<input class="rz-lookup-search-input" id="@SearchID" @ref="@search" tabindex="-1" placeholder="@SearchText"
|
||||
@onchange="@((args) => OnFilter(args))" @onkeydown="@((args) => OnFilterKeyPress(args))" value="@searchText" style="@(ShowSearch ? "" : "margin-right:0px;")" />
|
||||
@if (ShowSearch)
|
||||
{
|
||||
|
||||
@@ -59,6 +59,11 @@ namespace Radzen.Blazor
|
||||
/// </summary>
|
||||
protected virtual void OnRowRender(RowRenderEventArgs<object> args)
|
||||
{
|
||||
if (disabledPropertyGetter != null && disabledPropertyGetter(args.Data) as bool? == true)
|
||||
{
|
||||
args.Attributes.Add("class", "rz-data-row rz-state-disabled");
|
||||
}
|
||||
|
||||
if (RowRender != null)
|
||||
{
|
||||
RowRender(args);
|
||||
@@ -327,14 +332,41 @@ namespace Radzen.Blazor
|
||||
|
||||
if (AllowFilteringByAllStringColumns)
|
||||
{
|
||||
query = query.Where(string.Join(" || ", grid.ColumnsCollection.Where(c => c.Filterable && IsColumnFilterPropertyTypeString(c))
|
||||
.Select(c => GetPropertyFilterExpression(c.GetFilterProperty(), filterCaseSensitivityOperator))),
|
||||
FilterCaseSensitivity == FilterCaseSensitivity.CaseInsensitive ? searchText.ToLower() : searchText);
|
||||
if (AllowFilteringByWord)
|
||||
{
|
||||
string[] words = searchText.Split(' ');
|
||||
|
||||
foreach (string word in words)
|
||||
{
|
||||
query = query.Where(string.Join(" || ", grid.ColumnsCollection.Where(c => c.Filterable && IsColumnFilterPropertyTypeString(c))
|
||||
.Select(c => GetPropertyFilterExpression(c.GetFilterProperty(), filterCaseSensitivityOperator))),
|
||||
FilterCaseSensitivity == FilterCaseSensitivity.CaseInsensitive ? word.ToLower() : word);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
query = query.Where(string.Join(" || ", grid.ColumnsCollection.Where(c => c.Filterable && IsColumnFilterPropertyTypeString(c))
|
||||
.Select(c => GetPropertyFilterExpression(c.GetFilterProperty(), filterCaseSensitivityOperator))),
|
||||
FilterCaseSensitivity == FilterCaseSensitivity.CaseInsensitive ? searchText.ToLower() : searchText);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
query = query.Where($"{GetPropertyFilterExpression(TextProperty, filterCaseSensitivityOperator)}",
|
||||
FilterCaseSensitivity == FilterCaseSensitivity.CaseInsensitive ? searchText.ToLower() : searchText);
|
||||
if (AllowFilteringByWord)
|
||||
{
|
||||
string[] words = searchText.Split(' ');
|
||||
|
||||
foreach (string word in words)
|
||||
{
|
||||
query = query.Where($"{GetPropertyFilterExpression(TextProperty, filterCaseSensitivityOperator)}",
|
||||
FilterCaseSensitivity == FilterCaseSensitivity.CaseInsensitive ? word.ToLower() : word);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
query = query.Where($"{GetPropertyFilterExpression(TextProperty, filterCaseSensitivityOperator)}",
|
||||
FilterCaseSensitivity == FilterCaseSensitivity.CaseInsensitive ? searchText.ToLower() : searchText);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -595,6 +627,13 @@ namespace Radzen.Blazor
|
||||
[Parameter]
|
||||
public bool AllowFilteringByAllStringColumns { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether filtering by each entered word in the search term, sperated by a space, is allowed.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if filtering by individual words is allowed; otherwise, <c>false</c>.</value>
|
||||
[Parameter]
|
||||
public bool AllowFilteringByWord { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether DataGrid row can be selected on row click.
|
||||
/// </summary>
|
||||
|
||||
@@ -7,12 +7,12 @@
|
||||
@if (DropDown.Multiple)
|
||||
{
|
||||
<li class="@GetComponentCssClass("rz-multiselect")"
|
||||
aria-label="@DropDown.GetItemOrValueFromProperty(Item, DropDown.TextProperty)" style="display: block;white-space: nowrap;"
|
||||
aria-label="@DropDown.GetItemOrValueFromProperty(Item, DropDown.TextProperty)"
|
||||
@onmousedown:preventDefault @onmousedown="args=>SelectItem(args,false)"
|
||||
@onclick:preventDefault @onclick="args=>SelectItem(args,true)">
|
||||
<div class="rz-chkbox ">
|
||||
<div class="@(DropDown.isSelected(Item) ? "rz-chkbox-box rz-state-active" : "rz-chkbox-box") @(Disabled ? " rz-state-disabled " : "")">
|
||||
<span class="@(DropDown.isSelected(Item) ? "rz-chkbox-icon rzi rzi-check" : "rz-chkbox-icon")"></span>
|
||||
<div class="@(DropDown.IsSelected(Item) ? "rz-chkbox-box rz-state-active" : "rz-chkbox-box") @(Disabled ? " rz-state-disabled " : "")">
|
||||
<span class="@(DropDown.IsSelected(Item) ? "rz-chkbox-icon rzi rzi-check" : "rz-chkbox-icon")"></span>
|
||||
</div>
|
||||
</div>
|
||||
<span>
|
||||
@@ -69,7 +69,7 @@ else
|
||||
string result = $"{prefix}-item ";
|
||||
if (Disabled)
|
||||
result += "rz-state-disabled ";
|
||||
else if (DropDown.isSelected(Item))
|
||||
else if (DropDown.IsSelected(Item))
|
||||
result += "rz-state-highlight ";
|
||||
|
||||
return result;
|
||||
|
||||
@@ -497,15 +497,7 @@
|
||||
{
|
||||
if (column != null && !string.IsNullOrEmpty(column.FormatString))
|
||||
{
|
||||
var formats = column.FormatString.Split(new char[] { '{', '}' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
if (formats.Length > 0)
|
||||
{
|
||||
var format = formats[0].Trim().Split(':');
|
||||
if (format.Length > 1)
|
||||
{
|
||||
return format[1].Trim();
|
||||
}
|
||||
}
|
||||
return column.FormatString.Replace("{0:", "").Replace("}", "");
|
||||
}
|
||||
|
||||
return FilterDateFormat;
|
||||
|
||||
@@ -2,5 +2,5 @@
|
||||
|
||||
@if (Visible)
|
||||
{
|
||||
<label @ref="@Element" for="@Component" style="@Style" @attributes="Attributes" class="@GetCssClass()" id="@GetId()">@Text</label>
|
||||
<label @ref="@Element" for="@Component" style="@Style" @attributes="Attributes" class="@GetCssClass()" id="@GetId()">@if(ChildContent != null){@ChildContent}else{@Text}</label>
|
||||
}
|
||||
@@ -13,6 +13,13 @@ namespace Radzen.Blazor
|
||||
/// </example>
|
||||
public partial class RadzenLabel : RadzenComponent
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the child content.
|
||||
/// </summary>
|
||||
/// <value>The child content.</value>
|
||||
[Parameter]
|
||||
public RenderFragment ChildContent { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the component name for the label.
|
||||
/// </summary>
|
||||
|
||||
@@ -13,16 +13,7 @@
|
||||
|
||||
var value = ComposeValue(valueScale);
|
||||
|
||||
IPathGenerator pathGenerator;
|
||||
|
||||
if (Smooth)
|
||||
{
|
||||
pathGenerator = new SplineGenerator();
|
||||
}
|
||||
else
|
||||
{
|
||||
pathGenerator = new LineGenerator();
|
||||
}
|
||||
var pathGenerator = GetPathGenerator();
|
||||
|
||||
var data = Items.Select(item =>
|
||||
{
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using System;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Radzen.Blazor.Rendering;
|
||||
using System.Collections.Generic;
|
||||
@@ -34,7 +35,17 @@ namespace Radzen.Blazor
|
||||
/// Specifies whether to render a smooth line. Set to <c>false</c> by default.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public bool Smooth { get; set; }
|
||||
public bool Smooth
|
||||
{
|
||||
get => Interpolation == Interpolation.Spline;
|
||||
set => Interpolation = value ? Interpolation.Spline : Interpolation.Line;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Specifies how to render lines between data points. Set to <see cref="Line"/> by default
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public Interpolation Interpolation { get; set; } = Interpolation.Line;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string Color
|
||||
@@ -121,5 +132,20 @@ namespace Radzen.Blazor
|
||||
{
|
||||
return base.GetDataLabels(offsetX, offsetY - 16);
|
||||
}
|
||||
|
||||
private IPathGenerator GetPathGenerator()
|
||||
{
|
||||
switch(Interpolation)
|
||||
{
|
||||
case Interpolation.Line:
|
||||
return new LineGenerator();
|
||||
case Interpolation.Spline:
|
||||
return new SplineGenerator();
|
||||
case Interpolation.Step:
|
||||
return new StepGenerator();
|
||||
default:
|
||||
throw new NotSupportedException($"Interpolation {Interpolation} is not supported yet.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,15 @@
|
||||
{
|
||||
<i class="rzi">@((MarkupString)Icon)</i>
|
||||
}
|
||||
<span @ref="@Element" class="rz-link-text">@Text</span>
|
||||
<span @ref="@Element" class="rz-link-text">
|
||||
@if (ChildContent != null)
|
||||
{
|
||||
@ChildContent
|
||||
}
|
||||
else
|
||||
{
|
||||
@Text
|
||||
}
|
||||
</span>
|
||||
</Microsoft.AspNetCore.Components.Routing.NavLink>
|
||||
}
|
||||
|
||||
@@ -18,6 +18,13 @@ namespace Radzen.Blazor
|
||||
return "rz-link";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the child content.
|
||||
/// </summary>
|
||||
/// <value>The child content.</value>
|
||||
[Parameter]
|
||||
public RenderFragment ChildContent { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the target.
|
||||
/// </summary>
|
||||
|
||||
@@ -4,12 +4,12 @@
|
||||
@using Microsoft.JSInterop
|
||||
@typeparam TValue
|
||||
|
||||
<li class="@(ListBox.isSelected(Item) ? "rz-multiselect-item rz-state-highlight" : "rz-multiselect-item ")" aria-label="@PropertyAccess.GetItemOrValueFromProperty(Item, ListBox.TextProperty)" @onclick="@(async () => { if (!ListBox.Disabled) { await ListBox.SelectItemInternal(Item); } })">
|
||||
<li class="@(ListBox.IsSelected(Item) ? "rz-multiselect-item rz-state-highlight" : "rz-multiselect-item ")" aria-label="@PropertyAccess.GetItemOrValueFromProperty(Item, ListBox.TextProperty)" @onclick="@(async () => { if (!ListBox.Disabled) { await ListBox.SelectItemInternal(Item); } })">
|
||||
@if (ListBox.Multiple)
|
||||
{
|
||||
<div class="rz-chkbox ">
|
||||
<div class="@(ListBox.isSelected(Item) ? "rz-chkbox-box rz-state-active" : "rz-chkbox-box ")">
|
||||
<span class="@(ListBox.isSelected(Item) ? "rz-chkbox-icon rzi rzi-check" : "rz-chkbox-icon ")"></span>
|
||||
<div class="@(ListBox.IsSelected(Item) ? "rz-chkbox-box rz-state-active" : "rz-chkbox-box ")">
|
||||
<span class="@(ListBox.IsSelected(Item) ? "rz-chkbox-icon rzi rzi-check" : "rz-chkbox-icon ")"></span>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
@@ -200,17 +200,17 @@ namespace Radzen.Blazor
|
||||
{
|
||||
if (parameters.DidParameterChange(nameof(Username), Username))
|
||||
{
|
||||
username = Username;
|
||||
username = parameters.GetValueOrDefault<string>(nameof(Username));
|
||||
}
|
||||
|
||||
if (parameters.DidParameterChange(nameof(Password), Password))
|
||||
{
|
||||
password = Password;
|
||||
password = parameters.GetValueOrDefault<string>(nameof(Password));
|
||||
}
|
||||
|
||||
if (parameters.DidParameterChange(nameof(RememberMe), RememberMe))
|
||||
{
|
||||
rememberMe = RememberMe;
|
||||
rememberMe = parameters.GetValueOrDefault<bool>(nameof(RememberMe));
|
||||
}
|
||||
|
||||
await base.SetParametersAsync(parameters);
|
||||
@@ -222,7 +222,7 @@ namespace Radzen.Blazor
|
||||
/// <param name="args">The <see cref="EventArgs"/> instance containing the event data.</param>
|
||||
protected async Task OnReset(EventArgs args)
|
||||
{
|
||||
await ResetPassword.InvokeAsync(Username);
|
||||
await ResetPassword.InvokeAsync(username);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -25,6 +25,13 @@ namespace Radzen.Blazor
|
||||
[Parameter]
|
||||
public bool Responsive { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether this <see cref="RadzenMenu"/> should open item on click or on hover.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if open item on click; otherwise, <c>false</c> and items will open on hover.</value>
|
||||
[Parameter]
|
||||
public bool ClickToOpen { get; set; } = true;
|
||||
|
||||
private bool IsOpen { get; set; } = false;
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
@inherits RadzenComponent
|
||||
@if (Visible)
|
||||
{
|
||||
<li @attributes="Attributes" class="@GetCssClass()" style="@Style" @onclick="@OnClick" @onclick:stopPropagation>
|
||||
<div class="rz-navigation-item-wrapper" onclick="Radzen.toggleMenuItem(this)">
|
||||
<RadzenMenuItemWrapper Item="@this" @attributes="@Attributes" class="@GetCssClass()" style="@Style">
|
||||
<div class="rz-navigation-item-wrapper" @attributes="getOpenEvents()">
|
||||
@if (!string.IsNullOrEmpty(Path))
|
||||
{
|
||||
<NavLink target="@Target" class="rz-navigation-item-link" href="@Path">
|
||||
@@ -61,5 +61,5 @@
|
||||
@ChildContent
|
||||
</ul>
|
||||
}
|
||||
</li>
|
||||
</RadzenMenuItemWrapper>
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.AspNetCore.Components.Web;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Radzen.Blazor
|
||||
@@ -119,5 +121,21 @@ namespace Radzen.Blazor
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Dictionary<string, object> getOpenEvents()
|
||||
{
|
||||
var events = new Dictionary<string, object>();
|
||||
|
||||
if (Parent.ClickToOpen || ChildContent != null)
|
||||
{
|
||||
events.Add("onclick", "Radzen.toggleMenuItem(this)");
|
||||
}
|
||||
else
|
||||
{
|
||||
events.Add("onclick", "Radzen.toggleMenuItem(this, event, false)");
|
||||
}
|
||||
|
||||
return events;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
34
Radzen.Blazor/RadzenMenuItemWrapper.razor
Normal file
34
Radzen.Blazor/RadzenMenuItemWrapper.razor
Normal file
@@ -0,0 +1,34 @@
|
||||
@using Microsoft.AspNetCore.Components.Routing
|
||||
@inherits RadzenComponentWithChildren
|
||||
|
||||
@if (Item.Parent.ClickToOpen)
|
||||
{
|
||||
<li @attributes="@Attributes" @onclick="@Item.OnClick" @onclick:stopPropagation>
|
||||
@ChildContent
|
||||
</li>
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Item.ChildContent != null)
|
||||
{
|
||||
<li @attributes="@Attributes" onmouseenter="Radzen.toggleMenuItem(this, event, true)" onmouseleave="Radzen.toggleMenuItem(this, event, false)">
|
||||
@ChildContent
|
||||
</li>
|
||||
}
|
||||
else
|
||||
{
|
||||
<li @attributes="@Attributes" @onclick="@Item.OnClick" @onclick:stopPropagation>
|
||||
@ChildContent
|
||||
</li>
|
||||
}
|
||||
}
|
||||
|
||||
@code {
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the menu item.
|
||||
/// </summary>
|
||||
/// <value>The menu item.</value>
|
||||
[Parameter]
|
||||
public RadzenMenuItem Item { get; set; }
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.JSInterop;
|
||||
using Radzen.Blazor.Rendering;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
@@ -220,6 +219,12 @@ namespace Radzen.Blazor
|
||||
{
|
||||
valueStr = value.ToString();
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(Format))
|
||||
{
|
||||
valueStr = valueStr.Replace(Format.Replace("#", "").Trim(), "");
|
||||
}
|
||||
|
||||
return new string(valueStr.Where(c => char.IsDigit(c) || char.IsPunctuation(c)).ToArray()).Replace("%", "");
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using System;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
|
||||
namespace Radzen.Blazor
|
||||
{
|
||||
@@ -10,14 +11,14 @@ namespace Radzen.Blazor
|
||||
/// <code>
|
||||
/// <RadzenTemplateForm TItem="Model" Data=@model>
|
||||
/// <RadzenNumeric style="display: block" Name="Quantity" @bind-Value=@model.Quantity />
|
||||
/// <RadzenNumericRangeValidator Component="Quantity" Min="1" Max="10" Text="Quantity should be between 1 and 10" Style="position: absolute" />
|
||||
/// <RadzenNumericRangeValidator Component="Quantity" Min="1" Max="10" Text="Quantity should be between 1 and 10" Style="position: absolute" />
|
||||
/// </RadzenTemplateForm>
|
||||
/// @code {
|
||||
/// class Model
|
||||
/// {
|
||||
/// public decimal Quantity { get; set; }
|
||||
/// }
|
||||
/// Model model = new Model();
|
||||
/// Model model = new Model();
|
||||
/// }
|
||||
/// </code>
|
||||
/// </example>>
|
||||
@@ -33,30 +34,61 @@ namespace Radzen.Blazor
|
||||
/// Specifies the minimum value. The component value should be greater than the minimum in order to be valid.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public dynamic Min { get; set; }
|
||||
public IComparable Min { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Specifies the maximum value. The component value should be less than the maximum in order to be valid.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public dynamic Max { get; set; }
|
||||
public IComparable Max { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override bool Validate(IRadzenFormComponent component)
|
||||
{
|
||||
dynamic value = component.GetValue();
|
||||
if (Min == null && Max == null)
|
||||
{
|
||||
throw new ArgumentException("Min and Max cannot be both null");
|
||||
}
|
||||
|
||||
if (Min != null && ((value != null && value < Min) || value == null))
|
||||
object value = component.GetValue();
|
||||
|
||||
if (value == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Max != null && (value != null && value > Max))
|
||||
|
||||
if (Min != null)
|
||||
{
|
||||
return false;
|
||||
if (!TryConvertToType(value, Min.GetType(), out var convertedValue) || Min.CompareTo(convertedValue) > 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (Max != null)
|
||||
{
|
||||
if (!TryConvertToType(value, Max.GetType(), out var convertedValue) || Max.CompareTo(convertedValue) < 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool TryConvertToType(object value, Type type, out object convertedValue)
|
||||
{
|
||||
try
|
||||
{
|
||||
convertedValue = Convert.ChangeType(value, type);
|
||||
return true;
|
||||
}
|
||||
catch (InvalidCastException)
|
||||
{
|
||||
convertedValue = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,9 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.AspNetCore.Components.Routing;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Radzen.Blazor
|
||||
{
|
||||
@@ -20,6 +22,13 @@ namespace Radzen.Blazor
|
||||
/// </example>
|
||||
public partial class RadzenPanelMenu : RadzenComponentWithChildren
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether multiple items can be expanded.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if multiple items can be expanded; otherwise, <c>false</c>.</value>
|
||||
[Parameter]
|
||||
public bool Multiple { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the click callback.
|
||||
/// </summary>
|
||||
@@ -33,7 +42,7 @@ namespace Radzen.Blazor
|
||||
[Parameter]
|
||||
public NavLinkMatch Match { get; set; }
|
||||
|
||||
List<RadzenPanelMenuItem> items = new List<RadzenPanelMenuItem>();
|
||||
internal List<RadzenPanelMenuItem> items = new List<RadzenPanelMenuItem>();
|
||||
|
||||
/// <summary>
|
||||
/// Adds the item.
|
||||
@@ -70,6 +79,23 @@ namespace Radzen.Blazor
|
||||
UriHelper.LocationChanged -= UriHelper_OnLocationChanged;
|
||||
}
|
||||
|
||||
internal void CollapseAll(IEnumerable<RadzenPanelMenuItem> itemsToSkip)
|
||||
{
|
||||
items.Concat(items.SelectManyRecursive(i => i.items))
|
||||
.Where(i => !itemsToSkip.Contains(i)).ToList().ForEach(i => InvokeAsync(i.Collapse));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override async Task SetParametersAsync(ParameterView parameters)
|
||||
{
|
||||
if (parameters.DidParameterChange(nameof(Multiple), Multiple))
|
||||
{
|
||||
CollapseAll(Enumerable.Empty<RadzenPanelMenuItem>());
|
||||
}
|
||||
|
||||
await base.SetParametersAsync(parameters);
|
||||
}
|
||||
|
||||
bool ShouldMatch(string url)
|
||||
{
|
||||
if (string.IsNullOrEmpty(url))
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.AspNetCore.Components.Web;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Radzen.Blazor
|
||||
@@ -95,11 +96,34 @@ namespace Radzen.Blazor
|
||||
|
||||
async System.Threading.Tasks.Task Toggle()
|
||||
{
|
||||
if (!expanded && !Parent.Multiple)
|
||||
{
|
||||
var itemsToSkip = new List<RadzenPanelMenuItem>();
|
||||
var p = ParentItem;
|
||||
while (p != null)
|
||||
{
|
||||
itemsToSkip.Add(p);
|
||||
p = p.ParentItem;
|
||||
}
|
||||
|
||||
Parent.CollapseAll(itemsToSkip);
|
||||
}
|
||||
|
||||
expanded = !expanded;
|
||||
await ExpandedChanged.InvokeAsync(expanded);
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
internal async System.Threading.Tasks.Task Collapse()
|
||||
{
|
||||
if (expanded)
|
||||
{
|
||||
expanded = false;
|
||||
await ExpandedChanged.InvokeAsync(expanded);
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
|
||||
string getStyle()
|
||||
{
|
||||
string deg = expanded ? "180" : "0";
|
||||
@@ -164,7 +188,7 @@ namespace Radzen.Blazor
|
||||
}
|
||||
}
|
||||
|
||||
List<RadzenPanelMenuItem> items = new List<RadzenPanelMenuItem>();
|
||||
internal List<RadzenPanelMenuItem> items = new List<RadzenPanelMenuItem>();
|
||||
|
||||
/// <summary>
|
||||
/// Adds the item.
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<div @ref="@Element" style="@Style" @attributes="Attributes" class="@GetCssClass()" id="@GetId()">
|
||||
@foreach (var item in allItems.Where(i => i.Visible))
|
||||
{
|
||||
<div class="rz-radio-btn" @onclick="@(args => SelectItem(item))" @attributes="item.Attributes" style="@item.Style">
|
||||
<div @ref="@item.Element" id="@item.GetItemId()" @onclick="@(args => SelectItem(item))" @attributes="item.Attributes" class="@item.GetItemCssClass()" style="@item.Style">
|
||||
<div class="rz-radiobutton" @onkeypress="@(async args => { if (args.Code == "Space") { await SelectItem(item); } })" tabindex="@(Disabled || item.Disabled ? "-1" : $"{TabIndex}")">
|
||||
<div class="rz-helper-hidden-accessible">
|
||||
<input type="radio" disabled="@Disabled" name="@Name" value="@item.Value" tabindex="-1">
|
||||
|
||||
@@ -98,5 +98,21 @@ namespace Radzen.Blazor
|
||||
{
|
||||
Visible = value;
|
||||
}
|
||||
|
||||
internal string GetItemId()
|
||||
{
|
||||
return GetId();
|
||||
}
|
||||
|
||||
internal string GetItemCssClass()
|
||||
{
|
||||
return GetCssClass();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override string GetComponentCssClass()
|
||||
{
|
||||
return "rz-radio-btn";
|
||||
}
|
||||
}
|
||||
}
|
||||
6
Radzen.Blazor/RadzenRow.razor
Normal file
6
Radzen.Blazor/RadzenRow.razor
Normal file
@@ -0,0 +1,6 @@
|
||||
@inherits RadzenFlexComponent
|
||||
|
||||
@if (Visible)
|
||||
{
|
||||
<div @ref="@Element" @attributes="Attributes" class="@GetCssClass()" style="@GetStyle()" id="@GetId()">@ChildContent</div>
|
||||
}
|
||||
66
Radzen.Blazor/RadzenRow.razor.cs
Normal file
66
Radzen.Blazor/RadzenRow.razor.cs
Normal file
@@ -0,0 +1,66 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Radzen.Blazor
|
||||
{
|
||||
/// <summary>
|
||||
/// RadzenCard component.
|
||||
/// </summary>
|
||||
public partial class RadzenRow : RadzenFlexComponent
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the gap.
|
||||
/// </summary>
|
||||
/// <value>The gap.</value>
|
||||
[Parameter]
|
||||
public string Gap { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the row gap.
|
||||
/// </summary>
|
||||
/// <value>The row gap.</value>
|
||||
[Parameter]
|
||||
public string RowGap { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the final CSS style rendered by the component. Combines it with a <c>style</c> custom attribute.
|
||||
/// </summary>
|
||||
protected string GetStyle()
|
||||
{
|
||||
if (Attributes != null && Attributes.TryGetValue("style", out var style) && !string.IsNullOrEmpty(Convert.ToString(@style)))
|
||||
{
|
||||
return $"{GetComponentStyle()} {@style}";
|
||||
}
|
||||
|
||||
return GetComponentStyle();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the component CSS style.
|
||||
/// </summary>
|
||||
protected string GetComponentStyle()
|
||||
{
|
||||
var list = new List<string>();
|
||||
|
||||
if (!string.IsNullOrEmpty(Gap))
|
||||
{
|
||||
list.Add($"--rz-gap:{(Gap.All(char.IsDigit) ? Gap + "px" : Gap)}");
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(RowGap))
|
||||
{
|
||||
list.Add($"--rz-row-gap:{(RowGap.All(char.IsDigit) ? RowGap + "px" : RowGap)}");
|
||||
}
|
||||
|
||||
return $"{Style}{(!string.IsNullOrEmpty(Style) && !Style.EndsWith(";") ? ";" : "")}{string.Join(";", list)}";
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override string GetComponentCssClass()
|
||||
{
|
||||
return $"rz-display-flex rz-row rz-align-items-{GetFlexCSSClass<AlignItems>(AlignItems)} rz-justify-content-{GetFlexCSSClass<JustifyContent>(JustifyContent)}";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -206,7 +206,7 @@ namespace Radzen.Blazor
|
||||
|
||||
IList<ISchedulerView> Views { get; set; } = new List<ISchedulerView>();
|
||||
|
||||
ISchedulerView SelectedView
|
||||
public ISchedulerView SelectedView
|
||||
{
|
||||
get
|
||||
{
|
||||
|
||||
@@ -188,7 +188,7 @@ namespace Radzen.Blazor
|
||||
{
|
||||
var type = typeof(TValue).IsGenericType ? typeof(TValue).GetGenericArguments()[0] : typeof(TValue);
|
||||
|
||||
var selectedValues = Value != null ? ((IEnumerable)Value).AsQueryable().Cast(type).AsEnumerable().ToList() : new List<dynamic>();
|
||||
var selectedValues = Value != null ? QueryableExtension.ToList(((IEnumerable)Value).AsQueryable().Cast(type)) : new List<dynamic>();
|
||||
|
||||
if (!selectedValues.Contains(item.Value))
|
||||
{
|
||||
|
||||
3
Radzen.Blazor/RadzenSpeechToTextButton.razor
Normal file
3
Radzen.Blazor/RadzenSpeechToTextButton.razor
Normal file
@@ -0,0 +1,3 @@
|
||||
@inherits RadzenComponent
|
||||
<RadzenButton Visible="@Visible" id="@GetId()" title="@CurrentTitle" aria-label="@CurrentTitle" ButtonStyle="ButtonStyle" Icon="@CurrentIcon" style="@Style" @attributes="Attributes"
|
||||
class="@GetCssClass()" Click="OnSpeechToTextClicked"></RadzenButton>
|
||||
112
Radzen.Blazor/RadzenSpeechToTextButton.razor.cs
Normal file
112
Radzen.Blazor/RadzenSpeechToTextButton.razor.cs
Normal file
@@ -0,0 +1,112 @@
|
||||
using Microsoft.JSInterop;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
|
||||
namespace Radzen.Blazor
|
||||
{
|
||||
/// <summary>
|
||||
/// RadzenSpeechToTextButton component. Enables speech to text functionality.
|
||||
/// <para>This is only supported on select browsers. See https://caniuse.com/?search=SpeechRecognition</para>
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// <RadzenSpeechToTextButton Change=@(args => Console.WriteLine($"Value: {args}")) />
|
||||
/// </code>
|
||||
/// </example>
|
||||
/// </summary>
|
||||
public partial class RadzenSpeechToTextButton : RadzenComponent
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the button style.
|
||||
/// </summary>
|
||||
/// <value>The button style.</value>
|
||||
[Parameter]
|
||||
public ButtonStyle ButtonStyle { get; set; } = ButtonStyle.Light;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the icon displayed while not recording.
|
||||
/// </summary>
|
||||
/// <value>The icon.</value>
|
||||
[Parameter]
|
||||
public string Icon { get; set; } = "mic";
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the icon displayed while recording.
|
||||
/// </summary>
|
||||
/// <value>The icon.</value>
|
||||
[Parameter]
|
||||
public string StopIcon { get; set; } = "stop";
|
||||
|
||||
private string CurrentIcon => recording ? StopIcon : Icon;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the message displayed when user hovers the button and it is not recording.
|
||||
/// </summary>
|
||||
/// <value>The message.</value>
|
||||
[Parameter]
|
||||
public string Title { get; set; } = "Press to start speech recognition";
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the message displayed when user hovers the button and it is recording.
|
||||
/// </summary>
|
||||
/// <value>The message.</value>
|
||||
[Parameter]
|
||||
public string StopTitle { get; set; } = "Press to stop speech recognition";
|
||||
|
||||
private string CurrentTitle => recording ? StopTitle : Title;
|
||||
|
||||
/// <summary>
|
||||
/// Callback which provides results from the speech recognition API.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public EventCallback<string> Change { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the icon displayed while recording.
|
||||
/// </summary>
|
||||
/// <value>The icon.</value>
|
||||
[Parameter]
|
||||
public string Language { get; set; }
|
||||
|
||||
private bool recording;
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void OnAfterRender(bool firstRender)
|
||||
{
|
||||
base.OnAfterRender(firstRender);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override string GetComponentCssClass()
|
||||
{
|
||||
return recording ? "rz-speech-to-text-button rz-speech-to-text-button-recording" : "rz-speech-to-text-button";
|
||||
}
|
||||
|
||||
private async Task OnSpeechToTextClicked()
|
||||
{
|
||||
recording = !recording;
|
||||
|
||||
await JSRuntime.InvokeVoidAsync("Radzen.toggleDictation", Reference, Language);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Provides interface for javascript to stop speech to text recording on this component if another component starts recording.
|
||||
/// </summary>
|
||||
[JSInvokable]
|
||||
public void StopRecording()
|
||||
{
|
||||
recording = false;
|
||||
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Provides interface for javascript to pass speech results back to this component.
|
||||
/// </summary>
|
||||
/// <param name="result"></param>
|
||||
[JSInvokable]
|
||||
public void OnResult(string result)
|
||||
{
|
||||
Change.InvokeAsync(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -82,6 +82,13 @@ namespace Radzen.Blazor
|
||||
[Parameter]
|
||||
public bool Disabled { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the value indication behaviour to always open popup with item on click and not invoke <see cref="Click"/> event.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> to alway open popup with items; othersie, <c>false</c>. Default is <c>false</c>.</value>
|
||||
[Parameter]
|
||||
public bool AlwaysOpenPopup { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the click callback.
|
||||
/// </summary>
|
||||
@@ -97,8 +104,15 @@ namespace Radzen.Blazor
|
||||
{
|
||||
if (!Disabled)
|
||||
{
|
||||
await JSRuntime.InvokeVoidAsync("Radzen.closePopup", PopupID);
|
||||
await Click.InvokeAsync(null);
|
||||
if (AlwaysOpenPopup)
|
||||
{
|
||||
await JSRuntime.InvokeVoidAsync("Radzen.togglePopup", Element, PopupID);
|
||||
}
|
||||
else
|
||||
{
|
||||
await JSRuntime.InvokeVoidAsync("Radzen.closePopup", PopupID);
|
||||
await Click.InvokeAsync(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
@inherits RadzenComponent
|
||||
@if (Visible)
|
||||
{
|
||||
<li class="rz-menuitem" role="menuitem" @onclick="@OnClick" @attributes="Attributes" style="@Style">
|
||||
<a class="rz-menuitem-link">
|
||||
@if (!string.IsNullOrEmpty(Icon))
|
||||
{
|
||||
<span class="rz-menuitem-icon">@((MarkupString)Icon)</span>
|
||||
}
|
||||
@if (!string.IsNullOrEmpty(Text))
|
||||
{
|
||||
<span class="rz-menuitem-text">@Text</span>
|
||||
}
|
||||
</a>
|
||||
</li>
|
||||
<li class=@ItemClassList role="menuitem" @onclick="@OnClick" @attributes="Attributes" style="@Style">
|
||||
<a class="rz-menuitem-link">
|
||||
@if (!string.IsNullOrEmpty(Icon))
|
||||
{
|
||||
<span class="rz-menuitem-icon">@((MarkupString)Icon)</span>
|
||||
}
|
||||
@if (!string.IsNullOrEmpty(Text))
|
||||
{
|
||||
<span class="rz-menuitem-text">@Text</span>
|
||||
}
|
||||
</a>
|
||||
</li>
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.AspNetCore.Components.Web;
|
||||
using Radzen.Blazor.Rendering;
|
||||
|
||||
namespace Radzen.Blazor
|
||||
{
|
||||
@@ -29,6 +30,13 @@ namespace Radzen.Blazor
|
||||
[Parameter]
|
||||
public string Value { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether this <see cref="RadzenSplitButtonItem"/> is disabled.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if disabled; otherwise, <c>false</c>.</value>
|
||||
[Parameter]
|
||||
public bool Disabled { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the split button.
|
||||
/// </summary>
|
||||
@@ -43,11 +51,13 @@ namespace Radzen.Blazor
|
||||
/// <param name="args">The <see cref="MouseEventArgs"/> instance containing the event data.</param>
|
||||
public async System.Threading.Tasks.Task OnClick(MouseEventArgs args)
|
||||
{
|
||||
if (SplitButton != null)
|
||||
if (SplitButton != null && !Disabled)
|
||||
{
|
||||
SplitButton.Close();
|
||||
await SplitButton.Click.InvokeAsync(this);
|
||||
}
|
||||
}
|
||||
|
||||
ClassList ItemClassList => ClassList.Create("rz-menuitem").AddDisabled(Disabled);
|
||||
}
|
||||
}
|
||||
|
||||
6
Radzen.Blazor/RadzenStack.razor
Normal file
6
Radzen.Blazor/RadzenStack.razor
Normal file
@@ -0,0 +1,6 @@
|
||||
@inherits RadzenFlexComponent
|
||||
|
||||
@if (Visible)
|
||||
{
|
||||
<div @ref="@Element" @attributes="Attributes" class="@GetCssClass()" style="@GetStyle()" id="@GetId()">@ChildContent</div>
|
||||
}
|
||||
85
Radzen.Blazor/RadzenStack.razor.cs
Normal file
85
Radzen.Blazor/RadzenStack.razor.cs
Normal file
@@ -0,0 +1,85 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Radzen.Blazor
|
||||
{
|
||||
/// <summary>
|
||||
/// RadzenCard component.
|
||||
/// </summary>
|
||||
public partial class RadzenStack : RadzenFlexComponent
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the wrap.
|
||||
/// </summary>
|
||||
/// <value>The wrap.</value>
|
||||
[Parameter]
|
||||
public FlexWrap Wrap { get; set; } = FlexWrap.NoWrap;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the orientation.
|
||||
/// </summary>
|
||||
/// <value>The orientation.</value>
|
||||
[Parameter]
|
||||
public Orientation Orientation { get; set; } = Orientation.Vertical;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the spacing
|
||||
/// </summary>
|
||||
/// <value>The spacing.</value>
|
||||
[Parameter]
|
||||
public string Gap { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the reverse
|
||||
/// </summary>
|
||||
/// <value>The reverse.</value>
|
||||
[Parameter]
|
||||
public bool Reverse { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the final CSS style rendered by the component. Combines it with a <c>style</c> custom attribute.
|
||||
/// </summary>
|
||||
protected string GetStyle()
|
||||
{
|
||||
if (Attributes != null && Attributes.TryGetValue("style", out var style) && !string.IsNullOrEmpty(Convert.ToString(@style)))
|
||||
{
|
||||
return $"{GetComponentStyle()} {@style}";
|
||||
}
|
||||
|
||||
return GetComponentStyle();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the component CSS style.
|
||||
/// </summary>
|
||||
protected string GetComponentStyle()
|
||||
{
|
||||
var wrap = "";
|
||||
|
||||
if (Wrap == FlexWrap.Wrap)
|
||||
{
|
||||
wrap = ";flex-wrap:wrap;";
|
||||
}
|
||||
else if (Wrap == FlexWrap.NoWrap)
|
||||
{
|
||||
wrap = ";flex-wrap:nowrap;";
|
||||
}
|
||||
else if (Wrap == FlexWrap.WrapReverse)
|
||||
{
|
||||
wrap = ";flex-wrap:wrap-reverse;";
|
||||
}
|
||||
|
||||
return $"{Style}{(!string.IsNullOrEmpty(Style) && !Style.EndsWith(";") ? ";" : "")}{(!string.IsNullOrEmpty(Gap) ? "--rz-gap:" + Gap + (Gap.All(c => Char.IsDigit(c)) ? "px;" : "") : "")}{wrap}";
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override string GetComponentCssClass()
|
||||
{
|
||||
var horizontal = Orientation == Orientation.Horizontal;
|
||||
|
||||
return $"rz-stack rz-display-flex rz-flex-{(horizontal ? "row" : "column")}{(Reverse ? "-reverse" : "")} rz-align-items-{GetFlexCSSClass<AlignItems>(AlignItems)} rz-justify-content-{GetFlexCSSClass<JustifyContent>(JustifyContent)}";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -251,9 +251,9 @@ namespace Radzen.Blazor
|
||||
{
|
||||
if (Visible)
|
||||
{
|
||||
if (Data != null)
|
||||
if (EditContext != null)
|
||||
{
|
||||
builder.OpenRegion(Data.GetHashCode());
|
||||
builder.OpenRegion(EditContext.GetHashCode());
|
||||
}
|
||||
|
||||
builder.OpenElement(0, "form");
|
||||
@@ -287,7 +287,7 @@ namespace Radzen.Blazor
|
||||
|
||||
builder.CloseElement(); // form
|
||||
|
||||
if (Data != null)
|
||||
if (EditContext != null)
|
||||
{
|
||||
builder.CloseRegion();
|
||||
}
|
||||
|
||||
@@ -7,15 +7,14 @@
|
||||
@code {
|
||||
internal double Measure(RadzenChart chart)
|
||||
{
|
||||
if (Visible == false)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (chart.ShouldInvertAxes())
|
||||
{
|
||||
return AxisMeasurer.YAxis(chart.ValueScale, chart.CategoryAxis, chart.CategoryAxis.Title);
|
||||
}
|
||||
else if (Visible == false)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return AxisMeasurer.YAxis(chart.ValueScale, chart.ValueAxis, Title);
|
||||
|
||||
12
Radzen.Blazor/Rendering/ChartTooltipContainer.razor
Normal file
12
Radzen.Blazor/Rendering/ChartTooltipContainer.razor
Normal file
@@ -0,0 +1,12 @@
|
||||
@ChildContent
|
||||
|
||||
@code {
|
||||
[Parameter]
|
||||
public RenderFragment ChildContent { get; set; }
|
||||
|
||||
internal void Refresh()
|
||||
{
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -174,4 +174,34 @@
|
||||
{
|
||||
Service.OnRefresh -= OnRefresh;
|
||||
}
|
||||
|
||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||
{
|
||||
await base.OnAfterRenderAsync(firstRender);
|
||||
|
||||
if (firstRender)
|
||||
{
|
||||
var options = Dialog.Options;
|
||||
|
||||
var dialogOptions = new DialogOptions()
|
||||
{
|
||||
Width = options != null ? !string.IsNullOrEmpty(options.Width) ? options.Width : "" : "",
|
||||
Height = options != null ? options.Height : null,
|
||||
Left = options != null ? options.Left : null,
|
||||
Top = options != null ? options.Top : null,
|
||||
Bottom = options != null ? options.Bottom : null,
|
||||
ShowTitle = options != null ? options.ShowTitle : true,
|
||||
ShowClose = options != null ? options.ShowClose : true,
|
||||
Resizable = options != null ? options.Resizable : false,
|
||||
Draggable = options != null ? options.Draggable : false,
|
||||
Style = options != null ? options.Style : "",
|
||||
AutoFocusFirstElement = options != null ? options.AutoFocusFirstElement : true,
|
||||
CloseDialogOnOverlayClick = options != null ? options.CloseDialogOnOverlayClick : false,
|
||||
CloseDialogOnEsc = options != null ? options.CloseDialogOnEsc : true,
|
||||
CssClass = options != null ? options.CssClass : "",
|
||||
};
|
||||
|
||||
await JSRuntime.InvokeAsync<string>("Radzen.openDialog", dialogOptions, Service.Reference);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
@inherits RadzenComponent
|
||||
@using Microsoft.JSInterop
|
||||
<div @ref=@Element @onmousedown:preventDefault @attributes=@Attributes style=@Style id=@GetId()>
|
||||
<div @ref=@Element @attributes=@Attributes style=@Style id=@GetId()>
|
||||
@if (open || !Lazy)
|
||||
{
|
||||
@ChildContent
|
||||
|
||||
39
Radzen.Blazor/Rendering/StepGenerator.cs
Normal file
39
Radzen.Blazor/Rendering/StepGenerator.cs
Normal file
@@ -0,0 +1,39 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Radzen.Blazor.Rendering
|
||||
{
|
||||
/// <summary>
|
||||
/// Class StepGenerator.
|
||||
/// Implements the <see cref="Radzen.Blazor.Rendering.IPathGenerator" />
|
||||
/// </summary>
|
||||
/// <seealso cref="Radzen.Blazor.Rendering.IPathGenerator" />
|
||||
public class StepGenerator : IPathGenerator
|
||||
{
|
||||
/// <summary>
|
||||
/// Pathes the specified data.
|
||||
/// </summary>
|
||||
/// <param name="data">The data.</param>
|
||||
/// <returns>System.String.</returns>
|
||||
public string Path(IEnumerable<Point> data)
|
||||
{
|
||||
var path = new StringBuilder();
|
||||
var start = true;
|
||||
|
||||
foreach (var point in data)
|
||||
{
|
||||
if (start)
|
||||
{
|
||||
path.Append($"{point.X.ToInvariantString()} {point.Y.ToInvariantString()}");
|
||||
start = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
path.Append($" H {point.X.ToInvariantString()}");
|
||||
path.Append($" V {point.Y.ToInvariantString()}");
|
||||
}
|
||||
|
||||
return path.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
// Blazor
|
||||
@import 'components/blazor/utilities';
|
||||
@import 'components/blazor/spacing';
|
||||
@import 'components/blazor/typography';
|
||||
@import 'components/blazor/icons';
|
||||
@import 'components/blazor/common';
|
||||
@@ -64,4 +65,6 @@
|
||||
@import 'components/blazor/splitter';
|
||||
@import 'components/blazor/layout';
|
||||
@import 'components/blazor/breadcrumb';
|
||||
@import 'components/blazor/alert';
|
||||
@import 'components/blazor/alert';
|
||||
@import 'components/blazor/speech-to-text-button';
|
||||
@import 'components/blazor/stack';
|
||||
@@ -1,17 +1,37 @@
|
||||
@mixin rz-color-css($map, $attribute) {
|
||||
@mixin rz-color-css($property, $map) {
|
||||
@each $token,
|
||||
$value in $map {
|
||||
.rz-#{$attribute}-#{$token} {
|
||||
#{$attribute}: var(--rz-#{$token}) !important;
|
||||
.rz-#{$property}-#{$token} {
|
||||
#{$property}: var(--rz-#{$token}) !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@mixin rz-utility-css($map, $attribute) {
|
||||
@mixin rz-utility-map-css($property, $map) {
|
||||
@each $token,
|
||||
$value in $map {
|
||||
.rz-#{$token} {
|
||||
#{$attribute}: var(--rz-#{$token}) !important;
|
||||
#{$property}: var(--rz-#{$token}) !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@mixin rz-utility-list-css($property, $list) {
|
||||
@each $value in $list {
|
||||
.rz-#{$property}-#{$value} {
|
||||
#{$property}: #{$value} !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@mixin rz-utility-list-breakpoints-css($property, $list, $breakpoints) {
|
||||
@each $breakpoint, $breakpoint-value in $breakpoints {
|
||||
@media (min-width: #{$breakpoint-value}) {
|
||||
@each $value in $list {
|
||||
.rz-#{$property}-#{$breakpoint}-#{$value} {
|
||||
#{$property}: #{$value} !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,13 +6,15 @@ $card-heading-margin-bottom: 0.5rem !default;
|
||||
|
||||
// Card CSS variables
|
||||
|
||||
.rz-card {
|
||||
:root {
|
||||
--rz-card-padding: #{$card-padding};
|
||||
--rz-card-background-color: #{$card-background-color};
|
||||
--rz-card-shadow: #{$card-shadow};
|
||||
--rz-card-border-radius: #{$card-border-radius};
|
||||
--rz-card-heading-margin-bottom: #{$card-heading-margin-bottom};
|
||||
}
|
||||
|
||||
.rz-card {
|
||||
padding: var(--rz-card-padding);
|
||||
border-radius: var(--rz-card-border-radius);
|
||||
box-shadow: var(--rz-card-shadow);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
$chart-axis-color: var(--rz-base-300) !default;
|
||||
$chart-axis-label-color: var(--rz-text-secondary-color) !default;
|
||||
$chart-axis-font-size: 0.875rem !default;
|
||||
$chart-legend-font-size: 0.875rem !default;
|
||||
$chart-tooltip-background: var(--rz-base-background-color) !default;
|
||||
$chart-tooltip-color: var(--rz-text-color) !default;
|
||||
|
||||
@@ -13,7 +14,23 @@ $chart-color-schemes: (
|
||||
var(--rz-series-5),
|
||||
var(--rz-series-6),
|
||||
var(--rz-series-7),
|
||||
var(--rz-series-8)
|
||||
var(--rz-series-8),
|
||||
var(--rz-series-9),
|
||||
var(--rz-series-10),
|
||||
var(--rz-series-11),
|
||||
var(--rz-series-12),
|
||||
var(--rz-series-13),
|
||||
var(--rz-series-14),
|
||||
var(--rz-series-15),
|
||||
var(--rz-series-16),
|
||||
var(--rz-series-17),
|
||||
var(--rz-series-18),
|
||||
var(--rz-series-19),
|
||||
var(--rz-series-20),
|
||||
var(--rz-series-21),
|
||||
var(--rz-series-22),
|
||||
var(--rz-series-23),
|
||||
var(--rz-series-24)
|
||||
),
|
||||
palette: (
|
||||
#003f5c,
|
||||
@@ -54,6 +71,7 @@ $chart-color-schemes: (
|
||||
--rz-chart-axis-color: #{$chart-axis-color};
|
||||
--rz-chart-axis-label-color: #{$chart-axis-label-color};
|
||||
--rz-chart-axis-font-size: #{$chart-axis-font-size};
|
||||
--rz-chart-legend-font-size: #{$chart-legend-font-size};
|
||||
--rz-chart-tooltip-background: #{$chart-tooltip-background};
|
||||
--rz-chart-tooltip-color: #{$chart-tooltip-color};
|
||||
}
|
||||
@@ -180,6 +198,7 @@ $chart-color-schemes: (
|
||||
.rz-legend {
|
||||
position: absolute;
|
||||
display: flex;
|
||||
font-size: var(--rz-chart-legend-font-size);
|
||||
}
|
||||
|
||||
.rz-legend-right {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user