mirror of
https://gitee.com/ant-design-blazor/ant-design-blazor.git
synced 2024-12-02 03:57:38 +08:00
Merge feature to master (#1945)
* chore: sync ant-design v4.16.9 (#1782) * refactor(module: tree): rename Checked/Dechecked methods to Check/Uncheck (#1792) * feat(model: table): support responsive (#1802) * feat(module: form): add properties Help, ValidateStatus and HasFeedback (#1807) * Add properties Help, ValidateStatus and HasFeedback to FormItem * refactor validation messages Co-authored-by: ElderJames <shunjiey@hotmail.com> * feat(module: radio): add options for radio group (#1839) * feat(module: radio): support enum type for `RadioGroup` (#1840) * feat(module: image): support preview visible (#1842) * feat(module: tree): add ChildContent for Tree and TreeNode (#1887) * feat(module: tree): add ChildContent for Tree and TreeNode Allow user set tree nodes directly. * fix indent * docs: Update the style to be compatible with antd 4.16 style. (#1893) * docs: fix style * fix logo font * fix the color less * feat(module: TreeSelect): add tree-select component 🚀 (#1773) * fixed. Fix network error when requesting contributor list in local development environment * fixed. Fix Chinese garbled code * Update Dynamic.razor * update. Adjust the base class of the select control to selectbase, and extract the common methods to prepare for tree select. * fixed. Adjust the type of the parent control to selectbase * tree-select完成基础编码工作。 * fix. 重新修订冲突解决时误删的变量 * fix. 修复在多选模式下无法显示初始值的bug * fix some styles * add. tree add Node UnSelect Event * fix . Node Multiple Select Bug. * fix Tree UnSelect invalid. * fix. tree multiple select support. * fix. select option sync tree node selected. * fix. multiple select, old selected values has clear * fix loop update exception * 修复合并带来的冲突 * add. allow clear feat. but not finish. * fix merge bug * fix merge bug * fix. supplementary notes * update demo data with react demo * add. 添加静态下拉树的能力,以及单选和多选的demo * fix. 优化下拉显示树时,树选项的选中逻辑。 * fix demo * fix. 静态下拉树时,出现错选的bug * fix merge bugs. * fix merge bugs. * add. static dataObject Bind Support * 将下拉树中,对偏平数据源的处理,移到simpleTreeSelect中 * fix ChildrenExpression * feat: add dynamic component (#1703) * feat: weakly-typed/dynamic component * add TypeName support * override BuildRenderTree instead of using a RenderFragment * rename * fix(module: timeline): label missing (#1941) * chore: sync ant-design v4.16.13 (#1862) Co-authored-by: lukblazewicz <39852149+lukblazewicz@users.noreply.github.com> Co-authored-by: YongQuanRao <79885120+JamesGit-hash@users.noreply.github.com> Co-authored-by: anranruye <54608128+anranruye@users.noreply.github.com> Co-authored-by: Andrzej Bakun <andrzej@neelyc.com.cy> Co-authored-by: zxyao <zxyao145@gmail.com> Co-authored-by: Łukasz Błażewicz <lukasz.blazewicz@homebook.pl> Co-authored-by: heroboy <yangweiqin@gmail.com> Co-authored-by: Simon Cropp <simon.cropp@gmail.com> Co-authored-by: JohnHao421 <544106829@qq.com> Co-authored-by: haojiajun <haojiajun@vanelink.net> Co-authored-by: Noah Potash <digitalnugget@gmail.com> Co-authored-by: Noah Potash <noah.potash@outbreaklabs.com> Co-authored-by: SmallY <45689960+iamSmallY@users.noreply.github.com> Co-authored-by: Stefano Driussi <stedri@gmail.com> Co-authored-by: Stefano Drussi <stefano.driussi@hotmail.it> Co-authored-by: Guyiming <guyiming2011@126.com> Co-authored-by: Maksim <maksalmak@gmail.com> Co-authored-by: Nikolay Krondev <nikolaykrondev@users.noreply.github.com> Co-authored-by: gmij <gmij@qq.com> Co-authored-by: anranruye <hehewewe@hotmail.com> Co-authored-by: Alan.Liu <lxyruanjian@126.com> Co-authored-by: rabberbock <rabberbock@gmail.com> Co-authored-by: Andrzej Bakun <anddrzejb@poczta.fm> Co-authored-by: Chandan Rauniyar <chandankkrr@gmail.com> Co-authored-by: Luke Parker [SSW] <10430890+Hona@users.noreply.github.com> Co-authored-by: Tony Yip <tonyyip1969@gmail.com> Co-authored-by: SmRiley <45205313+SmRiley@users.noreply.github.com>
This commit is contained in:
commit
d27be8355e
@ -54,6 +54,11 @@
|
||||
box-shadow: 0 0 0 1px @shadow-color-inverse;
|
||||
}
|
||||
|
||||
// Tricky way to resolve https://github.com/ant-design/ant-design/issues/30088
|
||||
&-dot.@{number-prefix-cls} {
|
||||
transition: background 1.5s;
|
||||
}
|
||||
|
||||
&-count,
|
||||
&-dot,
|
||||
.@{number-prefix-cls}-custom-component {
|
||||
@ -157,7 +162,7 @@
|
||||
}
|
||||
|
||||
.@{number-prefix-cls}-custom-component,
|
||||
.@{ant-prefix}-scroll-number {
|
||||
.@{number-prefix-cls} {
|
||||
position: relative;
|
||||
top: auto;
|
||||
display: block;
|
||||
|
@ -101,7 +101,12 @@
|
||||
|
||||
&-icon-only {
|
||||
.btn-square(@btn-prefix-cls);
|
||||
vertical-align: -1px;
|
||||
vertical-align: -3px;
|
||||
|
||||
> .@{iconfont-css-prefix} {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
|
||||
&-round {
|
||||
@ -190,10 +195,15 @@
|
||||
margin-left: @margin-xs;
|
||||
}
|
||||
|
||||
&-background-ghost {
|
||||
&&-background-ghost {
|
||||
color: @btn-default-ghost-color;
|
||||
background: @btn-default-ghost-bg !important;
|
||||
border-color: @btn-default-ghost-border;
|
||||
&,
|
||||
&:hover,
|
||||
&:active,
|
||||
&:focus {
|
||||
background: @btn-default-ghost-bg;
|
||||
}
|
||||
}
|
||||
|
||||
&-background-ghost&-primary {
|
||||
|
@ -90,27 +90,27 @@
|
||||
.button-disabled();
|
||||
}
|
||||
.button-variant-ghost(@color; @border: @color) {
|
||||
.button-color(@color; transparent; @border);
|
||||
.button-color(@color; null; @border);
|
||||
text-shadow: none;
|
||||
&:hover,
|
||||
&:focus {
|
||||
& when (@border = transparent) {
|
||||
& when (@theme = dark) {
|
||||
.button-color(~`colorPalette('@{color}', 7) `; transparent; transparent);
|
||||
.button-color(~`colorPalette('@{color}', 7) `; null; transparent);
|
||||
}
|
||||
& when not (@theme = dark) {
|
||||
.button-color(~`colorPalette('@{color}', 5) `; transparent; transparent);
|
||||
.button-color(~`colorPalette('@{color}', 5) `; null; transparent);
|
||||
}
|
||||
}
|
||||
& when not (@border = transparent) {
|
||||
& when (@theme = dark) {
|
||||
.button-color(
|
||||
~`colorPalette('@{color}', 7) `; transparent; ~`colorPalette('@{color}', 7) `
|
||||
~`colorPalette('@{color}', 7) `; null; ~`colorPalette('@{color}', 7) `
|
||||
);
|
||||
}
|
||||
& when not (@theme = dark) {
|
||||
.button-color(
|
||||
~`colorPalette('@{color}', 5) `; transparent; ~`colorPalette('@{color}', 5) `
|
||||
~`colorPalette('@{color}', 5) `; null; ~`colorPalette('@{color}', 5) `
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -118,21 +118,21 @@
|
||||
&:active {
|
||||
& when (@border = transparent) {
|
||||
& when (@theme = dark) {
|
||||
.button-color(~`colorPalette('@{color}', 5) `; transparent; transparent);
|
||||
.button-color(~`colorPalette('@{color}', 5) `; null; transparent);
|
||||
}
|
||||
& when not (@theme = dark) {
|
||||
.button-color(~`colorPalette('@{color}', 7) `; transparent; transparent);
|
||||
.button-color(~`colorPalette('@{color}', 7) `; null; transparent);
|
||||
}
|
||||
}
|
||||
& when not(@border = transparent) {
|
||||
& when not (@border = transparent) {
|
||||
& when (@theme = dark) {
|
||||
.button-color(
|
||||
~`colorPalette('@{color}', 5) `; transparent; ~`colorPalette('@{color}', 5) `
|
||||
~`colorPalette('@{color}', 5) `; null; ~`colorPalette('@{color}', 5) `
|
||||
);
|
||||
}
|
||||
& when not (@theme = dark) {
|
||||
.button-color(
|
||||
~`colorPalette('@{color}', 7) `; transparent; ~`colorPalette('@{color}', 7) `
|
||||
~`colorPalette('@{color}', 7) `; null; ~`colorPalette('@{color}', 7) `
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -141,8 +141,10 @@
|
||||
}
|
||||
.button-color(@color; @background; @border) {
|
||||
color: @color;
|
||||
background: @background;
|
||||
border-color: @border; // a inside Button which only work in Chrome
|
||||
& when not(@background = null) {
|
||||
background: @background;
|
||||
}
|
||||
// http://stackoverflow.com/a/17253457
|
||||
> a:only-child {
|
||||
color: currentColor;
|
||||
|
@ -144,21 +144,21 @@
|
||||
&-hidden {
|
||||
display: none;
|
||||
}
|
||||
&.slide-up-enter.slide-up-enter-active&-placement-bottomLeft,
|
||||
&.slide-up-appear.slide-up-appear-active&-placement-bottomLeft {
|
||||
&.@{ant-prefix}-slide-up-enter.@{ant-prefix}-slide-up-enter-active&-placement-bottomLeft,
|
||||
&.@{ant-prefix}-slide-up-appear.@{ant-prefix}-slide-up-appear-active&-placement-bottomLeft {
|
||||
animation-name: antSlideUpIn;
|
||||
}
|
||||
|
||||
&.slide-up-enter.slide-up-enter-active&-placement-topLeft,
|
||||
&.slide-up-appear.slide-up-appear-active&-placement-topLeft {
|
||||
&.@{ant-prefix}-slide-up-enter.@{ant-prefix}-slide-up-enter-active&-placement-topLeft,
|
||||
&.@{ant-prefix}-slide-up-appear.@{ant-prefix}-slide-up-appear-active&-placement-topLeft {
|
||||
animation-name: antSlideDownIn;
|
||||
}
|
||||
|
||||
&.slide-up-leave.slide-up-leave-active&-placement-bottomLeft {
|
||||
&.@{ant-prefix}-slide-up-leave.@{ant-prefix}-slide-up-leave-active&-placement-bottomLeft {
|
||||
animation-name: antSlideUpOut;
|
||||
}
|
||||
|
||||
&.slide-up-leave.slide-up-leave-active&-placement-topLeft {
|
||||
&.@{ant-prefix}-slide-up-leave.@{ant-prefix}-slide-up-leave-active&-placement-topLeft {
|
||||
animation-name: antSlideDownOut;
|
||||
}
|
||||
}
|
||||
|
@ -60,7 +60,9 @@
|
||||
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 22%;
|
||||
// https://github.com/ant-design/ant-design/pull/19452
|
||||
// https://github.com/ant-design/ant-design/pull/31726
|
||||
left: 21.5%;
|
||||
display: table;
|
||||
width: @check-width;
|
||||
height: @check-height;
|
||||
|
@ -72,8 +72,12 @@
|
||||
padding-right: @collapse-header-padding-extra;
|
||||
|
||||
.@{collapse-prefix-cls}-arrow {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
right: @padding-md;
|
||||
left: auto;
|
||||
margin: 0;
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
52
components/core/DynamicComponent/Component.cs
Normal file
52
components/core/DynamicComponent/Component.cs
Normal file
@ -0,0 +1,52 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.AspNetCore.Components.Rendering;
|
||||
|
||||
namespace AntDesign
|
||||
{
|
||||
public class Component : ComponentBase
|
||||
{
|
||||
static Assembly _antAssembly;
|
||||
|
||||
[Parameter]
|
||||
public Type Type { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public string TypeName
|
||||
{
|
||||
set
|
||||
{
|
||||
if (Type != null) return;
|
||||
_antAssembly ??= Assembly.GetExecutingAssembly();
|
||||
Type componentType =
|
||||
_antAssembly.GetType($"AntDesign.{value}") ??
|
||||
_antAssembly.GetType(value) ??
|
||||
Type.GetType(value);
|
||||
if (componentType == null)
|
||||
{
|
||||
throw new ArgumentException($"Not found the component with the name \"{value}\"", nameof(TypeName));
|
||||
}
|
||||
Type = componentType;
|
||||
}
|
||||
}
|
||||
|
||||
[Parameter(CaptureUnmatchedValues = true)]
|
||||
public IDictionary<string, object> Parameters { get; set; }
|
||||
|
||||
protected override void BuildRenderTree(RenderTreeBuilder builder)
|
||||
{
|
||||
builder.OpenComponent(0, Type);
|
||||
if (Parameters != null)
|
||||
{
|
||||
builder.AddMultipleAttributes(1, Parameters);
|
||||
}
|
||||
builder.CloseComponent();
|
||||
}
|
||||
}
|
||||
}
|
@ -16,7 +16,7 @@ namespace AntDesign
|
||||
private static readonly Func<T, T, T> _aggregateFunction;
|
||||
|
||||
private static IEnumerable<T> _valueList;
|
||||
|
||||
private static IEnumerable<(T Value, string Label)> _valueLabelList;
|
||||
private static Type _enumType;
|
||||
|
||||
static EnumHelper()
|
||||
@ -24,6 +24,7 @@ namespace AntDesign
|
||||
_enumType = THelper.GetUnderlyingType<T>();
|
||||
_aggregateFunction = BuildAggregateFunction();
|
||||
_valueList = Enum.GetValues(_enumType).Cast<T>();
|
||||
_valueLabelList = _valueList.Select(value => (value, GetDisplayName(value)));
|
||||
}
|
||||
|
||||
// There is no constraint or type check for type parameter T, be sure that T is an enumeration type
|
||||
@ -49,11 +50,16 @@ namespace AntDesign
|
||||
return _valueList;
|
||||
}
|
||||
|
||||
public static string GetDisplayName(T t)
|
||||
public static IEnumerable<(T Value, string Label)> GetValueLabelList()
|
||||
{
|
||||
var fieldInfo = _enumType.GetField(t.ToString());
|
||||
return fieldInfo.GetCustomAttribute<DisplayAttribute>(true)?.Name ??
|
||||
fieldInfo.Name;
|
||||
return _valueLabelList;
|
||||
}
|
||||
|
||||
public static string GetDisplayName(T enumValue)
|
||||
{
|
||||
var enumName = Enum.GetName(_enumType, enumValue);
|
||||
var fieldInfo = _enumType.GetField(enumName);
|
||||
return fieldInfo.GetCustomAttribute<DisplayAttribute>(true)?.Name ?? enumName;
|
||||
}
|
||||
|
||||
private static Func<T, T, T> BuildAggregateFunction()
|
||||
|
@ -235,27 +235,27 @@
|
||||
}
|
||||
}
|
||||
|
||||
&.slide-up-enter.slide-up-enter-active&-placement-topLeft,
|
||||
&.slide-up-enter.slide-up-enter-active&-placement-topRight,
|
||||
&.slide-up-appear.slide-up-appear-active&-placement-topLeft,
|
||||
&.slide-up-appear.slide-up-appear-active&-placement-topRight {
|
||||
&.@{ant-prefix}-slide-up-enter.@{ant-prefix}-slide-up-enter-active&-placement-topLeft,
|
||||
&.@{ant-prefix}-slide-up-enter.@{ant-prefix}-slide-up-enter-active&-placement-topRight,
|
||||
&.@{ant-prefix}-slide-up-appear.@{ant-prefix}-slide-up-appear-active&-placement-topLeft,
|
||||
&.@{ant-prefix}-slide-up-appear.@{ant-prefix}-slide-up-appear-active&-placement-topRight {
|
||||
animation-name: antSlideDownIn;
|
||||
}
|
||||
|
||||
&.slide-up-enter.slide-up-enter-active&-placement-bottomLeft,
|
||||
&.slide-up-enter.slide-up-enter-active&-placement-bottomRight,
|
||||
&.slide-up-appear.slide-up-appear-active&-placement-bottomLeft,
|
||||
&.slide-up-appear.slide-up-appear-active&-placement-bottomRight {
|
||||
&.@{ant-prefix}-slide-up-enter.@{ant-prefix}-slide-up-enter-active&-placement-bottomLeft,
|
||||
&.@{ant-prefix}-slide-up-enter.@{ant-prefix}-slide-up-enter-active&-placement-bottomRight,
|
||||
&.@{ant-prefix}-slide-up-appear.@{ant-prefix}-slide-up-appear-active&-placement-bottomLeft,
|
||||
&.@{ant-prefix}-slide-up-appear.@{ant-prefix}-slide-up-appear-active&-placement-bottomRight {
|
||||
animation-name: antSlideUpIn;
|
||||
}
|
||||
|
||||
&.slide-up-leave.slide-up-leave-active&-placement-topLeft,
|
||||
&.slide-up-leave.slide-up-leave-active&-placement-topRight {
|
||||
&.@{ant-prefix}-slide-up-leave.@{ant-prefix}-slide-up-leave-active&-placement-topLeft,
|
||||
&.@{ant-prefix}-slide-up-leave.@{ant-prefix}-slide-up-leave-active&-placement-topRight {
|
||||
animation-name: antSlideDownOut;
|
||||
}
|
||||
|
||||
&.slide-up-leave.slide-up-leave-active&-placement-bottomLeft,
|
||||
&.slide-up-leave.slide-up-leave-active&-placement-bottomRight {
|
||||
&.@{ant-prefix}-slide-up-leave.@{ant-prefix}-slide-up-leave-active&-placement-bottomLeft,
|
||||
&.@{ant-prefix}-slide-up-leave.@{ant-prefix}-slide-up-leave-active&-placement-bottomRight {
|
||||
animation-name: antSlideUpOut;
|
||||
}
|
||||
}
|
||||
@ -346,6 +346,11 @@
|
||||
border-width: 0 0 @border-width-base 0;
|
||||
border-radius: 0;
|
||||
|
||||
.@{picker-prefix-cls}-content,
|
||||
table {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
&-focused {
|
||||
border-color: @border-color-split;
|
||||
}
|
||||
|
@ -161,6 +161,7 @@
|
||||
z-index: 1;
|
||||
height: @picker-panel-cell-height;
|
||||
transform: translateY(-50%);
|
||||
transition: all @animation-duration-slow;
|
||||
content: '';
|
||||
}
|
||||
|
||||
@ -247,6 +248,7 @@
|
||||
border-top: @border-width-base dashed @picker-date-hover-range-border-color;
|
||||
border-bottom: @border-width-base dashed @picker-date-hover-range-border-color;
|
||||
transform: translateY(-50%);
|
||||
transition: all @animation-duration-slow;
|
||||
content: '';
|
||||
}
|
||||
}
|
||||
@ -292,6 +294,7 @@
|
||||
bottom: 0;
|
||||
z-index: -1;
|
||||
background: @picker-date-hover-range-color;
|
||||
transition: all @animation-duration-slow;
|
||||
content: '';
|
||||
}
|
||||
}
|
||||
@ -340,10 +343,10 @@
|
||||
|
||||
// >>> Disabled
|
||||
&-disabled {
|
||||
color: @disabled-color;
|
||||
pointer-events: none;
|
||||
|
||||
.@{cellClassName} {
|
||||
color: @disabled-color;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
@ -366,11 +369,6 @@
|
||||
color: @text-color;
|
||||
}
|
||||
|
||||
// Disabled
|
||||
&-disabled {
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.picker-cell-inner(~'@{picker-cell-inner-cls}');
|
||||
}
|
||||
|
||||
@ -385,12 +383,6 @@
|
||||
.@{picker-cell-inner-cls} {
|
||||
padding: 0 @padding-xs;
|
||||
}
|
||||
|
||||
.@{picker-prefix-cls}-cell {
|
||||
&-disabled .@{picker-cell-inner-cls} {
|
||||
background: @picker-basic-cell-disabled-bg;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-quarter-panel {
|
||||
|
@ -128,6 +128,7 @@
|
||||
border: 1px solid @border-color-split;
|
||||
> table {
|
||||
table-layout: auto;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -32,7 +32,7 @@
|
||||
}
|
||||
|
||||
.@{iconfont-css-prefix}-down::before {
|
||||
transition: transform 0.2s;
|
||||
transition: transform @animation-duration-base;
|
||||
}
|
||||
}
|
||||
|
||||
@ -133,7 +133,7 @@
|
||||
&-item-group-title {
|
||||
padding: 5px @control-padding-horizontal;
|
||||
color: @text-color-secondary;
|
||||
transition: all 0.3s;
|
||||
transition: all @animation-duration-slow;
|
||||
}
|
||||
|
||||
&-submenu-popup {
|
||||
@ -154,6 +154,42 @@
|
||||
}
|
||||
}
|
||||
|
||||
// ======================= Item Content =======================
|
||||
&-item {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
&-item-icon {
|
||||
min-width: 12px;
|
||||
margin-right: 8px;
|
||||
font-size: @font-size-sm;
|
||||
}
|
||||
|
||||
&-title-content {
|
||||
flex: auto;
|
||||
|
||||
> a {
|
||||
color: inherit;
|
||||
transition: all @animation-duration-slow;
|
||||
|
||||
&:hover {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
&::after {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
content: '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// =========================== Item ===========================
|
||||
&-item,
|
||||
&-submenu-title {
|
||||
clear: both;
|
||||
@ -165,35 +201,7 @@
|
||||
line-height: @dropdown-line-height;
|
||||
white-space: nowrap;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
|
||||
> .@{iconfont-css-prefix}:first-child,
|
||||
> a > .@{iconfont-css-prefix}:first-child,
|
||||
> span > .@{iconfont-css-prefix}:first-child {
|
||||
min-width: 12px;
|
||||
margin-right: 8px;
|
||||
font-size: @font-size-sm;
|
||||
vertical-align: -0.1em;
|
||||
}
|
||||
|
||||
> a {
|
||||
display: block;
|
||||
margin: -5px -@control-padding-horizontal;
|
||||
padding: 5px @control-padding-horizontal;
|
||||
color: @text-color;
|
||||
transition: all 0.3s;
|
||||
&:hover {
|
||||
color: @text-color;
|
||||
}
|
||||
}
|
||||
|
||||
> .@{iconfont-css-prefix} + span > a {
|
||||
color: @text-color;
|
||||
transition: all 0.3s;
|
||||
&:hover {
|
||||
color: @text-color;
|
||||
}
|
||||
}
|
||||
transition: all @animation-duration-slow;
|
||||
|
||||
&:first-child {
|
||||
& when (@dropdown-edge-child-vertical-padding = 0) {
|
||||
@ -207,8 +215,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
&-selected,
|
||||
&-selected > a {
|
||||
&-selected {
|
||||
color: @dropdown-selected-color;
|
||||
background-color: @item-active-bg;
|
||||
}
|
||||
@ -227,21 +234,8 @@
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
> .@{iconfont-css-prefix} + span > a,
|
||||
> a {
|
||||
position: relative;
|
||||
color: @disabled-color;
|
||||
a {
|
||||
pointer-events: none;
|
||||
|
||||
&::after {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
cursor: not-allowed;
|
||||
content: '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -304,33 +298,33 @@
|
||||
}
|
||||
}
|
||||
|
||||
&.slide-down-enter.slide-down-enter-active&-placement-bottomLeft,
|
||||
&.slide-down-appear.slide-down-appear-active&-placement-bottomLeft,
|
||||
&.slide-down-enter.slide-down-enter-active&-placement-bottomCenter,
|
||||
&.slide-down-appear.slide-down-appear-active&-placement-bottomCenter,
|
||||
&.slide-down-enter.slide-down-enter-active&-placement-bottomRight,
|
||||
&.slide-down-appear.slide-down-appear-active&-placement-bottomRight {
|
||||
&.@{ant-prefix}-slide-down-enter.@{ant-prefix}-slide-down-enter-active&-placement-bottomLeft,
|
||||
&.@{ant-prefix}-slide-down-appear.@{ant-prefix}-slide-down-appear-active&-placement-bottomLeft,
|
||||
&.@{ant-prefix}-slide-down-enter.@{ant-prefix}-slide-down-enter-active&-placement-bottomCenter,
|
||||
&.@{ant-prefix}-slide-down-appear.@{ant-prefix}-slide-down-appear-active&-placement-bottomCenter,
|
||||
&.@{ant-prefix}-slide-down-enter.@{ant-prefix}-slide-down-enter-active&-placement-bottomRight,
|
||||
&.@{ant-prefix}-slide-down-appear.@{ant-prefix}-slide-down-appear-active&-placement-bottomRight {
|
||||
animation-name: antSlideUpIn;
|
||||
}
|
||||
|
||||
&.slide-up-enter.slide-up-enter-active&-placement-topLeft,
|
||||
&.slide-up-appear.slide-up-appear-active&-placement-topLeft,
|
||||
&.slide-up-enter.slide-up-enter-active&-placement-topCenter,
|
||||
&.slide-up-appear.slide-up-appear-active&-placement-topCenter,
|
||||
&.slide-up-enter.slide-up-enter-active&-placement-topRight,
|
||||
&.slide-up-appear.slide-up-appear-active&-placement-topRight {
|
||||
&.@{ant-prefix}-slide-up-enter.@{ant-prefix}-slide-up-enter-active&-placement-topLeft,
|
||||
&.@{ant-prefix}-slide-up-appear.@{ant-prefix}-slide-up-appear-active&-placement-topLeft,
|
||||
&.@{ant-prefix}-slide-up-enter.@{ant-prefix}-slide-up-enter-active&-placement-topCenter,
|
||||
&.@{ant-prefix}-slide-up-appear.@{ant-prefix}-slide-up-appear-active&-placement-topCenter,
|
||||
&.@{ant-prefix}-slide-up-enter.@{ant-prefix}-slide-up-enter-active&-placement-topRight,
|
||||
&.@{ant-prefix}-slide-up-appear.@{ant-prefix}-slide-up-appear-active&-placement-topRight {
|
||||
animation-name: antSlideDownIn;
|
||||
}
|
||||
|
||||
&.slide-down-leave.slide-down-leave-active&-placement-bottomLeft,
|
||||
&.slide-down-leave.slide-down-leave-active&-placement-bottomCenter,
|
||||
&.slide-down-leave.slide-down-leave-active&-placement-bottomRight {
|
||||
&.@{ant-prefix}-slide-down-leave.@{ant-prefix}-slide-down-leave-active&-placement-bottomLeft,
|
||||
&.@{ant-prefix}-slide-down-leave.@{ant-prefix}-slide-down-leave-active&-placement-bottomCenter,
|
||||
&.@{ant-prefix}-slide-down-leave.@{ant-prefix}-slide-down-leave-active&-placement-bottomRight {
|
||||
animation-name: antSlideUpOut;
|
||||
}
|
||||
|
||||
&.slide-up-leave.slide-up-leave-active&-placement-topLeft,
|
||||
&.slide-up-leave.slide-up-leave-active&-placement-topCenter,
|
||||
&.slide-up-leave.slide-up-leave-active&-placement-topRight {
|
||||
&.@{ant-prefix}-slide-up-leave.@{ant-prefix}-slide-up-leave-active&-placement-topLeft,
|
||||
&.@{ant-prefix}-slide-up-leave.@{ant-prefix}-slide-up-leave-active&-placement-topCenter,
|
||||
&.@{ant-prefix}-slide-up-leave.@{ant-prefix}-slide-up-leave-active&-placement-topRight {
|
||||
animation-name: antSlideDownOut;
|
||||
}
|
||||
}
|
||||
|
@ -16,6 +16,7 @@
|
||||
}
|
||||
</AntDesign.Col>
|
||||
}
|
||||
|
||||
<AntDesign.Col @attributes="GetWrapperColAttributes()" Class=@($"{_prefixCls}-control")>
|
||||
<div class=@($"{_prefixCls}-control-input")>
|
||||
<div class=@($"{_prefixCls}-control-input-content")>
|
||||
@ -23,7 +24,19 @@
|
||||
@ChildContent
|
||||
</CascadingValue>
|
||||
</div>
|
||||
@if (IsShowIcon)
|
||||
{
|
||||
<span class=@($"{_prefixCls}-children-icon")><Icon Type="@(_iconMap[ValidateStatus].type)" Theme="@(_iconMap[ValidateStatus].theme)" /></span>
|
||||
}
|
||||
</div>
|
||||
@_formValidationMessages
|
||||
|
||||
@foreach (var message in _validationMessages)
|
||||
{
|
||||
<div class=@($"{_prefixCls}-explain {_prefixCls}-explain-{(_isValid ? "default" : "error")}")>
|
||||
<div role="alert">
|
||||
@message
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</AntDesign.Col>
|
||||
</Row>
|
@ -4,6 +4,7 @@ using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text.Json;
|
||||
using System.Threading.Tasks;
|
||||
using AntDesign.Core.Reflection;
|
||||
using AntDesign.Forms;
|
||||
using AntDesign.Internal;
|
||||
@ -11,6 +12,7 @@ using AntDesign.Internal.Form.Validate;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.AspNetCore.Components.Forms;
|
||||
using OneOf;
|
||||
using static AntDesign.IconType;
|
||||
|
||||
namespace AntDesign
|
||||
{
|
||||
@ -107,16 +109,35 @@ namespace AntDesign
|
||||
[Parameter]
|
||||
public FormValidationRule[] Rules { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public bool HasFeedback { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public FormValidateStatus ValidateStatus { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public string Help { get; set; }
|
||||
|
||||
private static readonly Dictionary<FormValidateStatus, (string theme, string type)> _iconMap = new Dictionary<FormValidateStatus, (string theme, string type)>
|
||||
{
|
||||
{ FormValidateStatus.Success, (IconThemeType.Fill, Outline.CheckCircle) },
|
||||
{ FormValidateStatus.Warning, (IconThemeType.Fill, Outline.ExclamationCircle) },
|
||||
{ FormValidateStatus.Error, (IconThemeType.Fill, Outline.CloseCircle) },
|
||||
{ FormValidateStatus.Validating, (IconThemeType.Outline, Outline.Loading) }
|
||||
};
|
||||
|
||||
private bool IsShowIcon => HasFeedback && _iconMap.ContainsKey(ValidateStatus);
|
||||
|
||||
private EditContext EditContext => Form?.EditContext;
|
||||
|
||||
private string[] _validationMessages = Array.Empty<string>();
|
||||
|
||||
private bool _isValid = true;
|
||||
|
||||
private string _labelCls = "";
|
||||
|
||||
private IControlValueAccessor _control;
|
||||
|
||||
private RenderFragment _formValidationMessages;
|
||||
|
||||
private PropertyReflector _propertyReflector;
|
||||
|
||||
private ClassMapper _labelClassMapper = new ClassMapper();
|
||||
@ -140,6 +161,11 @@ namespace AntDesign
|
||||
SetRequiredCss();
|
||||
|
||||
Form.AddFormItem(this);
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(Help))
|
||||
{
|
||||
_validationMessages = new[] { Help };
|
||||
}
|
||||
}
|
||||
|
||||
protected void SetClass()
|
||||
@ -148,6 +174,10 @@ namespace AntDesign
|
||||
.Add(_prefixCls)
|
||||
.If($"{_prefixCls}-with-help {_prefixCls}-has-error", () => _isValid == false)
|
||||
.If($"{_prefixCls}-rtl", () => RTL)
|
||||
.If($"{_prefixCls}-has-feedback", () => HasFeedback)
|
||||
.If($"{_prefixCls}-is-validating", () => ValidateStatus == FormValidateStatus.Validating)
|
||||
.GetIf(() => $"{_prefixCls}-has-{ValidateStatus.ToString().ToLower()}", () => ValidateStatus.IsIn(FormValidateStatus.Success, FormValidateStatus.Error, FormValidateStatus.Warning))
|
||||
.If($"{_prefixCls}-with-help", () => !string.IsNullOrEmpty(Help))
|
||||
;
|
||||
|
||||
_labelClassMapper
|
||||
@ -257,7 +287,6 @@ namespace AntDesign
|
||||
_fieldIdentifier = control.FieldIdentifier;
|
||||
this._control = control;
|
||||
|
||||
|
||||
if (Form.ValidateMode.IsIn(FormValidateMode.Rules, FormValidateMode.Complex))
|
||||
{
|
||||
_fieldPropertyInfo = _fieldIdentifier.Model.GetType().GetProperty(_fieldIdentifier.FieldName);
|
||||
@ -265,22 +294,20 @@ namespace AntDesign
|
||||
|
||||
_validationStateChangedHandler = (s, e) =>
|
||||
{
|
||||
control.ValidationMessages = CurrentEditContext.GetValidationMessages(control.FieldIdentifier).Distinct().ToArray();
|
||||
this._isValid = !control.ValidationMessages.Any();
|
||||
_validationMessages = CurrentEditContext.GetValidationMessages(control.FieldIdentifier).Distinct().ToArray();
|
||||
this._isValid = !_validationMessages.Any();
|
||||
control.ValidationMessages = _validationMessages;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(Help))
|
||||
{
|
||||
_validationMessages = new[] { Help };
|
||||
}
|
||||
|
||||
StateHasChanged();
|
||||
};
|
||||
|
||||
CurrentEditContext.OnValidationStateChanged += _validationStateChangedHandler;
|
||||
|
||||
_formValidationMessages = builder =>
|
||||
{
|
||||
var i = 0;
|
||||
builder.OpenComponent<FormValidationMessage<TValue>>(i++);
|
||||
builder.AddAttribute(i++, "Control", control);
|
||||
builder.CloseComponent();
|
||||
};
|
||||
|
||||
if (control.ValueExpression is not null)
|
||||
_propertyReflector = PropertyReflector.Create(control.ValueExpression);
|
||||
else
|
||||
|
11
components/form/FormValidateStatus.cs
Normal file
11
components/form/FormValidateStatus.cs
Normal file
@ -0,0 +1,11 @@
|
||||
namespace AntDesign
|
||||
{
|
||||
public enum FormValidateStatus
|
||||
{
|
||||
Default,
|
||||
Success,
|
||||
Warning,
|
||||
Error,
|
||||
Validating
|
||||
}
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
@namespace AntDesign
|
||||
@typeparam TValue
|
||||
|
||||
@foreach (var message in _control.ValidationMessages)
|
||||
{
|
||||
<FormValidationMessageItem AdditionalAttributes="@AdditionalAttributes" Message="@message" @key="message"></FormValidationMessageItem>
|
||||
}
|
@ -1,62 +0,0 @@
|
||||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq.Expressions;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.AspNetCore.Components.Forms;
|
||||
|
||||
namespace AntDesign
|
||||
{
|
||||
/// <summary>
|
||||
/// FormValidationMessage is copy from ValidationMessage.
|
||||
/// Displays a list of validation messages for a specified field within a cascaded <see cref="EditContext"/>.
|
||||
/// </summary>
|
||||
public partial class FormValidationMessage<TValue> : ComponentBase, IDisposable
|
||||
{
|
||||
private EditContext _previousEditContext;
|
||||
private Expression<Func<TValue>> _previousFieldAccessor;
|
||||
|
||||
//private readonly EventHandler<ValidationStateChangedEventArgs> _validationStateChangedHandler;
|
||||
private FieldIdentifier _fieldIdentifier;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a collection of additional attributes that will be applied to the created <c>div</c> element.
|
||||
/// </summary>
|
||||
[Parameter(CaptureUnmatchedValues = true)]
|
||||
public IReadOnlyDictionary<string, object> AdditionalAttributes { get; set; }
|
||||
|
||||
[CascadingParameter]
|
||||
private EditContext CurrentEditContext { get; set; }
|
||||
|
||||
public AntInputComponentBase<TValue> _control;
|
||||
|
||||
[Parameter]
|
||||
public AntInputComponentBase<TValue> Control
|
||||
{
|
||||
get
|
||||
{
|
||||
return _control;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value != null && _control != value)
|
||||
{
|
||||
_control = value;
|
||||
_fieldIdentifier = _control.FieldIdentifier;
|
||||
_previousFieldAccessor = _control.ValueExpression;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
}
|
||||
|
||||
void IDisposable.Dispose()
|
||||
{
|
||||
Dispose(disposing: true);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
@namespace AntDesign
|
||||
|
||||
<div @attributes="@AdditionalAttributes" class="ant-form-item-explain ant-form-item-explain-error">@Message</div>
|
@ -1,16 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
|
||||
namespace AntDesign
|
||||
{
|
||||
public partial class FormValidationMessageItem
|
||||
{
|
||||
[Parameter]
|
||||
public string Message { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public IReadOnlyDictionary<string, object> AdditionalAttributes { get; set; }
|
||||
}
|
||||
}
|
@ -89,9 +89,9 @@
|
||||
|
||||
> label {
|
||||
position: relative;
|
||||
// display: inline;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
max-width: 100%;
|
||||
height: @form-item-label-height;
|
||||
color: @label-color;
|
||||
font-size: @form-item-label-font-size;
|
||||
@ -235,27 +235,33 @@
|
||||
@keyframes diffZoomIn1 {
|
||||
0% {
|
||||
transform: scale(0);
|
||||
opacity: 0;
|
||||
}
|
||||
100% {
|
||||
transform: scale(1);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes diffZoomIn2 {
|
||||
0% {
|
||||
transform: scale(0);
|
||||
opacity: 0;
|
||||
}
|
||||
100% {
|
||||
transform: scale(1);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes diffZoomIn3 {
|
||||
0% {
|
||||
transform: scale(0);
|
||||
opacity: 0;
|
||||
}
|
||||
100% {
|
||||
transform: scale(1);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5,8 +5,8 @@
|
||||
color: @text-color;
|
||||
}
|
||||
// 输入框的不同校验状态
|
||||
.@{ant-prefix}-input,
|
||||
.@{ant-prefix}-input-affix-wrapper {
|
||||
:not(.@{ant-prefix}-input-disabled):not(.@{ant-prefix}-input-borderless).@{ant-prefix}-input,
|
||||
:not(.@{ant-prefix}-input-affix-wrapper-disabled):not(.@{ant-prefix}-input-affix-wrapper-borderless).@{ant-prefix}-input-affix-wrapper {
|
||||
&,
|
||||
&:hover {
|
||||
background-color: @background-color;
|
||||
@ -19,26 +19,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
.@{ant-prefix}-input-disabled {
|
||||
&,
|
||||
&:hover {
|
||||
background-color: @input-disabled-bg;
|
||||
border-color: @input-border-color;
|
||||
}
|
||||
}
|
||||
|
||||
.@{ant-prefix}-input-affix-wrapper-disabled {
|
||||
&,
|
||||
&:hover {
|
||||
background-color: @input-disabled-bg;
|
||||
border-color: @input-border-color;
|
||||
|
||||
input:focus {
|
||||
box-shadow: none !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.@{ant-prefix}-calendar-picker-open .@{ant-prefix}-calendar-picker-input {
|
||||
.active(@border-color);
|
||||
}
|
||||
|
@ -6,7 +6,8 @@
|
||||
<img alt="@Alt" class="ant-image-img" src="@Src" style="@Style"
|
||||
@onerror="HandleOnError"
|
||||
@onloadstart="HandleOnLoadStart"
|
||||
@onload="HandleOnLoad" />
|
||||
@onload="HandleOnLoad"
|
||||
@onclick="OnClick"/>
|
||||
|
||||
@if (!_loaded && Placeholder != null)
|
||||
{
|
||||
@ -17,7 +18,7 @@
|
||||
|
||||
@if (_loaded && !_isError && Preview)
|
||||
{
|
||||
<div class="ant-image-mask" @onclick="OnPreview">
|
||||
<div class="ant-image-mask" @onclick="OnPreview" @onclick:stopPropagation>
|
||||
<div class="ant-image-mask-info">
|
||||
<Icon Type="eye" /> @Locale.Preview
|
||||
</div>
|
||||
|
@ -26,6 +26,9 @@ namespace AntDesign
|
||||
[Parameter]
|
||||
public bool Preview { get; set; } = true;
|
||||
|
||||
[Parameter]
|
||||
public bool PreviewVisible { get; set; } = true;
|
||||
|
||||
[Parameter]
|
||||
public string Src
|
||||
{
|
||||
@ -49,6 +52,9 @@ namespace AntDesign
|
||||
[Parameter]
|
||||
public string PreviewSrc { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public EventCallback<MouseEventArgs> OnClick { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public ImageLocale Locale { get; set; } = LocaleProvider.CurrentLocale.Image;
|
||||
|
||||
@ -108,14 +114,22 @@ namespace AntDesign
|
||||
_loaded = false;
|
||||
}
|
||||
|
||||
private void OnPreview()
|
||||
private void OnPreview(MouseEventArgs e)
|
||||
{
|
||||
var images = Group?.Images ?? new List<Image>() { this };
|
||||
var index = images.IndexOf(this);
|
||||
if (PreviewVisible)
|
||||
{
|
||||
var images = Group?.Images ?? new List<Image>() { this };
|
||||
var index = images.IndexOf(this);
|
||||
|
||||
_imageRef = ImageService.OpenImages(images);
|
||||
_imageRef = ImageService.OpenImages(images);
|
||||
|
||||
_imageRef.SwitchTo(index);
|
||||
_imageRef.SwitchTo(index);
|
||||
}
|
||||
|
||||
if (OnClick.HasDelegate)
|
||||
{
|
||||
OnClick.InvokeAsync(e);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
|
@ -5,15 +5,38 @@ using Microsoft.AspNetCore.Components;
|
||||
|
||||
namespace AntDesign
|
||||
{
|
||||
public partial class ImagePreviewGroup
|
||||
public partial class ImagePreviewGroup : IDisposable
|
||||
{
|
||||
[Parameter]
|
||||
public RenderFragment ChildContent { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public bool PreviewVisible
|
||||
{
|
||||
get => _previewVisible;
|
||||
set
|
||||
{
|
||||
if (_previewVisible != value)
|
||||
{
|
||||
_previewVisible = value;
|
||||
HandleVisibleChange(_previewVisible);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Parameter]
|
||||
public EventCallback<bool> PreviewVisibleChanged { get; set; }
|
||||
|
||||
[Inject]
|
||||
private ImageService ImageService { get; set; }
|
||||
|
||||
internal IList<Image> Images => _images;
|
||||
|
||||
private IList<Image> _images;
|
||||
|
||||
private ImageRef _imageRef;
|
||||
private bool _previewVisible = true;
|
||||
|
||||
public void AddImage(Image image)
|
||||
{
|
||||
_images ??= new List<Image>();
|
||||
@ -24,5 +47,41 @@ namespace AntDesign
|
||||
{
|
||||
_images.Remove(image);
|
||||
}
|
||||
|
||||
public void HandleVisibleChange(bool visible)
|
||||
{
|
||||
if (visible)
|
||||
{
|
||||
_imageRef = ImageService.OpenImages(_images);
|
||||
_imageRef.SwitchTo(0);
|
||||
_imageRef.OnClosed += OnPreviewClose;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_imageRef != null)
|
||||
{
|
||||
_imageRef.OnClosed -= OnPreviewClose;
|
||||
ImageService.CloseImage(_imageRef);
|
||||
}
|
||||
}
|
||||
|
||||
if (PreviewVisibleChanged.HasDelegate)
|
||||
{
|
||||
PreviewVisibleChanged.InvokeAsync(visible);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnPreviewClose()
|
||||
{
|
||||
PreviewVisible = false;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (_imageRef != null)
|
||||
{
|
||||
_imageRef.OnClosed -= OnPreviewClose;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,8 @@ namespace AntDesign
|
||||
{
|
||||
public class ImageRef
|
||||
{
|
||||
public event Action OnClosed;
|
||||
|
||||
internal string ImageSrc => _showingImageSrc;
|
||||
|
||||
internal int CurrentIndex => _currentIndex;
|
||||
@ -36,6 +38,7 @@ namespace AntDesign
|
||||
|
||||
public void Close()
|
||||
{
|
||||
OnClosed?.Invoke();
|
||||
_imageService.CloseImage(this);
|
||||
}
|
||||
}
|
||||
|
@ -26,6 +26,7 @@
|
||||
font-weight: bold;
|
||||
line-height: 0;
|
||||
text-align: center;
|
||||
border-left: @border-width-base @border-style-base @input-number-handler-border-color;
|
||||
transition: all 0.1s linear;
|
||||
&:active {
|
||||
background: @input-number-handler-active-bg;
|
||||
@ -123,7 +124,6 @@
|
||||
width: 22px;
|
||||
height: 100%;
|
||||
background: @input-number-handler-bg;
|
||||
border-left: @border-width-base @border-style-base @input-number-handler-border-color;
|
||||
border-radius: 0 @border-radius-base @border-radius-base 0;
|
||||
opacity: 0;
|
||||
transition: opacity 0.24s linear 0.1s;
|
||||
|
@ -33,7 +33,7 @@
|
||||
outline: none;
|
||||
|
||||
&:focus {
|
||||
box-shadow: none;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
@import './index';
|
||||
|
||||
// ========================= Input =========================
|
||||
.@{ant-prefix}-input-clear-icon {
|
||||
margin: 0 @input-affix-margin;
|
||||
.@{iconfont-css-prefix}.@{ant-prefix}-input-clear-icon {
|
||||
margin: 0;
|
||||
color: @disabled-color;
|
||||
font-size: @font-size-sm;
|
||||
vertical-align: -1px;
|
||||
@ -23,8 +23,8 @@
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
margin-right: 0;
|
||||
&-has-suffix {
|
||||
margin: 0 @input-affix-margin;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4,15 +4,17 @@
|
||||
@import './affix';
|
||||
@import './allow-clear';
|
||||
|
||||
@input-prefix-cls: ~'@{ant-prefix}-input';
|
||||
|
||||
// Input styles
|
||||
.@{ant-prefix}-input {
|
||||
.@{input-prefix-cls} {
|
||||
.reset-component();
|
||||
.input();
|
||||
|
||||
//== Style for input-group: input with label, with button or dropdown...
|
||||
&-group {
|
||||
.reset-component();
|
||||
.input-group(~'@{ant-prefix}-input');
|
||||
.input-group(~'@{input-prefix-cls}');
|
||||
&-wrapper {
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
@ -34,10 +36,10 @@
|
||||
&[type='color'] {
|
||||
height: @input-height-base;
|
||||
|
||||
&.@{ant-prefix}-input-lg {
|
||||
&.@{input-prefix-cls}-lg {
|
||||
height: @input-height-lg;
|
||||
}
|
||||
&.@{ant-prefix}-input-sm {
|
||||
&.@{input-prefix-cls}-sm {
|
||||
height: @input-height-sm;
|
||||
padding-top: 3px;
|
||||
padding-bottom: 3px;
|
||||
|
@ -36,6 +36,8 @@
|
||||
.disabled() {
|
||||
color: @input-disabled-color;
|
||||
background-color: @input-disabled-bg;
|
||||
border-color: @input-border-color;
|
||||
box-shadow: none;
|
||||
cursor: not-allowed;
|
||||
opacity: 1;
|
||||
|
||||
@ -205,6 +207,17 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// https://github.com/ant-design/ant-design/issues/31333
|
||||
.@{ant-prefix}-cascader-picker {
|
||||
margin: -9px (-@control-padding-horizontal);
|
||||
background-color: transparent;
|
||||
.@{ant-prefix}-cascader-input {
|
||||
text-align: left;
|
||||
border: 0;
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Reset rounded corners
|
||||
|
@ -47,10 +47,10 @@
|
||||
|
||||
// allow-clear
|
||||
.@{ant-prefix}-input-clear-icon {
|
||||
&:last-child {
|
||||
&-has-suffix {
|
||||
.@{ant-prefix}-input-affix-wrapper-rtl & {
|
||||
margin-right: @input-affix-margin;
|
||||
margin-left: 0;
|
||||
margin-right: 0;
|
||||
margin-left: @input-affix-margin;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -87,8 +87,7 @@
|
||||
> span > a {
|
||||
color: @menu-dark-highlight-color;
|
||||
}
|
||||
> .@{menu-prefix-cls}-submenu-title,
|
||||
> .@{menu-prefix-cls}-submenu-title:hover {
|
||||
> .@{menu-prefix-cls}-submenu-title {
|
||||
> .@{menu-prefix-cls}-submenu-arrow {
|
||||
opacity: 1;
|
||||
&::after,
|
||||
|
@ -40,6 +40,15 @@
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
// Overflow ellipsis
|
||||
&-overflow {
|
||||
display: flex;
|
||||
|
||||
&-item {
|
||||
flex: none;
|
||||
}
|
||||
}
|
||||
|
||||
&-hidden,
|
||||
&-submenu-hidden {
|
||||
display: none;
|
||||
@ -80,6 +89,10 @@
|
||||
padding @animation-duration-slow @ease-in-out;
|
||||
}
|
||||
|
||||
&-title-content {
|
||||
transition: color @animation-duration-slow;
|
||||
}
|
||||
|
||||
&-item a {
|
||||
color: @menu-item-color;
|
||||
&:hover {
|
||||
@ -111,14 +124,6 @@
|
||||
background-color: @border-color-split;
|
||||
}
|
||||
|
||||
&-item:hover,
|
||||
&-item-active,
|
||||
&:not(&-inline) &-submenu-open,
|
||||
&-submenu-active,
|
||||
&-submenu-title:hover {
|
||||
color: @menu-highlight-color;
|
||||
}
|
||||
|
||||
&-horizontal &-item,
|
||||
&-horizontal &-submenu {
|
||||
margin-top: -1px;
|
||||
@ -211,8 +216,6 @@
|
||||
+ span {
|
||||
margin-left: @menu-icon-margin-right;
|
||||
opacity: 1;
|
||||
// transition: opacity @animation-duration-slow @ease-in-out,
|
||||
// width @animation-duration-slow @ease-in-out, color @animation-duration-slow;
|
||||
transition: opacity @animation-duration-slow @ease-in-out, margin @animation-duration-slow,
|
||||
color @animation-duration-slow;
|
||||
}
|
||||
@ -365,19 +368,19 @@
|
||||
&:not(.@{menu-prefix-cls}-dark) {
|
||||
> .@{menu-prefix-cls}-item,
|
||||
> .@{menu-prefix-cls}-submenu {
|
||||
margin: @menu-item-padding;
|
||||
margin-top: -1px;
|
||||
margin-bottom: 0;
|
||||
padding: @menu-item-padding;
|
||||
padding-right: 0;
|
||||
padding-left: 0;
|
||||
|
||||
&:hover,
|
||||
&-active,
|
||||
&-open,
|
||||
&-selected {
|
||||
color: @menu-highlight-color;
|
||||
border-bottom: 2px solid @menu-highlight-color;
|
||||
|
||||
&::after {
|
||||
border-bottom: 2px solid @menu-highlight-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -388,7 +391,16 @@
|
||||
top: 1px;
|
||||
display: inline-block;
|
||||
vertical-align: bottom;
|
||||
border-bottom: 2px solid transparent;
|
||||
|
||||
&::after {
|
||||
position: absolute;
|
||||
right: @menu-item-padding-horizontal;
|
||||
bottom: 0;
|
||||
left: @menu-item-padding-horizontal;
|
||||
border-bottom: 2px solid transparent;
|
||||
transition: border-color @animation-duration-slow @ease-in-out;
|
||||
content: '';
|
||||
}
|
||||
}
|
||||
|
||||
> .@{menu-prefix-cls}-submenu > .@{menu-prefix-cls}-submenu-title {
|
||||
@ -625,8 +637,12 @@
|
||||
&-submenu-disabled {
|
||||
color: @disabled-color !important;
|
||||
background: none;
|
||||
border-color: transparent !important;
|
||||
cursor: not-allowed;
|
||||
|
||||
&::after {
|
||||
border-color: transparent !important;
|
||||
}
|
||||
|
||||
a {
|
||||
color: @disabled-color !important;
|
||||
pointer-events: none;
|
||||
@ -651,5 +667,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
@import './light';
|
||||
@import './dark';
|
||||
@import './rtl';
|
||||
|
12
components/menu/style/light.less
Normal file
12
components/menu/style/light.less
Normal file
@ -0,0 +1,12 @@
|
||||
.@{menu-prefix-cls} {
|
||||
// light theme
|
||||
&-light {
|
||||
.@{menu-prefix-cls}-item:hover,
|
||||
.@{menu-prefix-cls}-item-active,
|
||||
.@{menu-prefix-cls}:not(.@{menu-prefix-cls}-inline) .@{menu-prefix-cls}-submenu-open,
|
||||
.@{menu-prefix-cls}-submenu-active,
|
||||
.@{menu-prefix-cls}-submenu-title:hover {
|
||||
color: @menu-highlight-color;
|
||||
}
|
||||
}
|
||||
}
|
@ -51,7 +51,7 @@
|
||||
font-size: @font-size-lg;
|
||||
}
|
||||
|
||||
&-notice.move-up-leave.move-up-leave-active {
|
||||
&-notice.@{ant-prefix}-move-up-leave.@{ant-prefix}-move-up-leave-active {
|
||||
animation-name: MessageMoveOut;
|
||||
animation-duration: 0.3s;
|
||||
}
|
||||
|
@ -377,7 +377,6 @@
|
||||
|
||||
&-active {
|
||||
background: @pagination-item-disabled-bg-active;
|
||||
border-color: transparent;
|
||||
a {
|
||||
color: @pagination-item-disabled-color-active;
|
||||
}
|
||||
|
@ -3,6 +3,11 @@
|
||||
|
||||
@popover-prefix-cls: ~'@{ant-prefix}-popover';
|
||||
|
||||
@popover-arrow-rotate-width: sqrt(@popover-arrow-width * @popover-arrow-width * 2);
|
||||
|
||||
@popover-arrow-offset-vertical: 12px;
|
||||
@popover-arrow-offset-horizontal: 16px;
|
||||
|
||||
.@{popover-prefix-cls} {
|
||||
.reset-component();
|
||||
|
||||
@ -109,102 +114,139 @@
|
||||
}
|
||||
|
||||
// Arrows
|
||||
// .popover-arrow is outer, .popover-arrow:after is inner
|
||||
|
||||
&-arrow {
|
||||
position: absolute;
|
||||
display: block;
|
||||
width: sqrt(@popover-arrow-width * @popover-arrow-width * 2);
|
||||
height: sqrt(@popover-arrow-width * @popover-arrow-width * 2);
|
||||
width: @popover-arrow-rotate-width;
|
||||
height: @popover-arrow-rotate-width;
|
||||
overflow: hidden;
|
||||
background: transparent;
|
||||
border-style: solid;
|
||||
border-width: (sqrt(@popover-arrow-width * @popover-arrow-width * 2) / 2);
|
||||
transform: rotate(45deg);
|
||||
pointer-events: none;
|
||||
|
||||
&-content {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
display: block;
|
||||
width: @popover-arrow-width;
|
||||
height: @popover-arrow-width;
|
||||
margin: auto;
|
||||
background-color: @popover-bg;
|
||||
content: '';
|
||||
pointer-events: auto;
|
||||
}
|
||||
}
|
||||
|
||||
&-placement-top > &-content > &-arrow,
|
||||
&-placement-topLeft > &-content > &-arrow,
|
||||
&-placement-topRight > &-content > &-arrow {
|
||||
bottom: @popover-distance - @popover-arrow-width + 2.2px;
|
||||
border-top-color: transparent;
|
||||
border-right-color: @popover-bg;
|
||||
border-bottom-color: @popover-bg;
|
||||
border-left-color: transparent;
|
||||
box-shadow: 3px 3px 7px fade(@black, 7%);
|
||||
&-placement-top &-arrow,
|
||||
&-placement-topLeft &-arrow,
|
||||
&-placement-topRight &-arrow {
|
||||
bottom: @popover-distance - @popover-arrow-rotate-width;
|
||||
|
||||
&-content {
|
||||
box-shadow: 3px 3px 7px fade(@black, 7%);
|
||||
transform: translateY((-@popover-arrow-rotate-width / 2)) rotate(45deg);
|
||||
}
|
||||
}
|
||||
&-placement-top > &-content > &-arrow {
|
||||
&-placement-top &-arrow {
|
||||
left: 50%;
|
||||
transform: translateX(-50%) rotate(45deg);
|
||||
}
|
||||
&-placement-topLeft > &-content > &-arrow {
|
||||
left: 16px;
|
||||
}
|
||||
&-placement-topRight > &-content > &-arrow {
|
||||
right: 16px;
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
|
||||
&-placement-right > &-content > &-arrow,
|
||||
&-placement-rightTop > &-content > &-arrow,
|
||||
&-placement-rightBottom > &-content > &-arrow {
|
||||
left: @popover-distance - @popover-arrow-width + 2px;
|
||||
border-top-color: transparent;
|
||||
border-right-color: transparent;
|
||||
border-bottom-color: @popover-bg;
|
||||
border-left-color: @popover-bg;
|
||||
box-shadow: -3px 3px 7px fade(@black, 7%);
|
||||
&-placement-topLeft &-arrow {
|
||||
left: @popover-arrow-offset-horizontal;
|
||||
}
|
||||
&-placement-right > &-content > &-arrow {
|
||||
|
||||
&-placement-topRight &-arrow {
|
||||
right: @popover-arrow-offset-horizontal;
|
||||
}
|
||||
|
||||
&-placement-right &-arrow,
|
||||
&-placement-rightTop &-arrow,
|
||||
&-placement-rightBottom &-arrow {
|
||||
left: @popover-distance - @popover-arrow-rotate-width;
|
||||
|
||||
&-content {
|
||||
box-shadow: -3px 3px 7px fade(@black, 7%);
|
||||
transform: translateX((@popover-arrow-rotate-width / 2)) rotate(45deg);
|
||||
}
|
||||
}
|
||||
&-placement-right &-arrow {
|
||||
top: 50%;
|
||||
transform: translateY(-50%) rotate(45deg);
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
&-placement-rightTop > &-content > &-arrow {
|
||||
top: 12px;
|
||||
&-placement-rightTop &-arrow {
|
||||
top: @popover-arrow-offset-vertical;
|
||||
}
|
||||
&-placement-rightBottom > &-content > &-arrow {
|
||||
bottom: 12px;
|
||||
&-placement-rightBottom &-arrow {
|
||||
bottom: @popover-arrow-offset-vertical;
|
||||
}
|
||||
|
||||
&-placement-bottom > &-content > &-arrow,
|
||||
&-placement-bottomLeft > &-content > &-arrow,
|
||||
&-placement-bottomRight > &-content > &-arrow {
|
||||
top: @popover-distance - @popover-arrow-width + 2px;
|
||||
border-top-color: @popover-bg;
|
||||
border-right-color: transparent;
|
||||
border-bottom-color: transparent;
|
||||
border-left-color: @popover-bg;
|
||||
box-shadow: -2px -2px 5px fade(@black, 6%);
|
||||
&-placement-bottom &-arrow,
|
||||
&-placement-bottomLeft &-arrow,
|
||||
&-placement-bottomRight &-arrow {
|
||||
top: @popover-distance - @popover-arrow-rotate-width;
|
||||
|
||||
&-content {
|
||||
box-shadow: -2px -2px 5px fade(@black, 6%);
|
||||
transform: translateY((@popover-arrow-rotate-width / 2)) rotate(45deg);
|
||||
}
|
||||
}
|
||||
&-placement-bottom > &-content > &-arrow {
|
||||
|
||||
&-placement-bottom &-arrow {
|
||||
left: 50%;
|
||||
transform: translateX(-50%) rotate(45deg);
|
||||
}
|
||||
&-placement-bottomLeft > &-content > &-arrow {
|
||||
left: 16px;
|
||||
}
|
||||
&-placement-bottomRight > &-content > &-arrow {
|
||||
right: 16px;
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
|
||||
&-placement-left > &-content > &-arrow,
|
||||
&-placement-leftTop > &-content > &-arrow,
|
||||
&-placement-leftBottom > &-content > &-arrow {
|
||||
right: @popover-distance - @popover-arrow-width + 2px;
|
||||
border-top-color: @popover-bg;
|
||||
border-right-color: @popover-bg;
|
||||
border-bottom-color: transparent;
|
||||
border-left-color: transparent;
|
||||
box-shadow: 3px -3px 7px fade(@black, 7%);
|
||||
&-placement-bottomLeft &-arrow {
|
||||
left: @popover-arrow-offset-horizontal;
|
||||
}
|
||||
&-placement-left > &-content > &-arrow {
|
||||
|
||||
&-placement-bottomRight &-arrow {
|
||||
right: @popover-arrow-offset-horizontal;
|
||||
}
|
||||
|
||||
&-placement-left &-arrow,
|
||||
&-placement-leftTop &-arrow,
|
||||
&-placement-leftBottom &-arrow {
|
||||
right: @popover-distance - @popover-arrow-rotate-width;
|
||||
|
||||
&-content {
|
||||
box-shadow: 3px -3px 7px fade(@black, 7%);
|
||||
transform: translateX((-@popover-arrow-rotate-width / 2)) rotate(45deg);
|
||||
}
|
||||
}
|
||||
|
||||
&-placement-left &-arrow {
|
||||
top: 50%;
|
||||
transform: translateY(-50%) rotate(45deg);
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
&-placement-leftTop > &-content > &-arrow {
|
||||
top: 12px;
|
||||
|
||||
&-placement-leftTop &-arrow {
|
||||
top: @popover-arrow-offset-vertical;
|
||||
}
|
||||
&-placement-leftBottom > &-content > &-arrow {
|
||||
bottom: 12px;
|
||||
|
||||
&-placement-leftBottom &-arrow {
|
||||
bottom: @popover-arrow-offset-vertical;
|
||||
}
|
||||
}
|
||||
|
||||
.generator-popover-preset-color(@i: length(@preset-colors)) when (@i > 0) {
|
||||
.generator-popover-preset-color(@i - 1);
|
||||
@color: extract(@preset-colors, @i);
|
||||
@lightColor: '@{color}-6';
|
||||
.@{popover-prefix-cls}-@{color} {
|
||||
.@{popover-prefix-cls}-inner {
|
||||
background-color: @@lightColor;
|
||||
}
|
||||
.@{popover-prefix-cls}-arrow {
|
||||
&-content {
|
||||
background-color: @@lightColor;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.generator-popover-preset-color();
|
||||
|
||||
@import './rtl';
|
||||
|
@ -189,15 +189,15 @@
|
||||
|
||||
@keyframes ~"@{ant-prefix}-progress-active" {
|
||||
0% {
|
||||
width: 0;
|
||||
transform: translateX(-100%) scaleX(0);
|
||||
opacity: 0.1;
|
||||
}
|
||||
20% {
|
||||
width: 0;
|
||||
transform: translateX(-100%) scaleX(0);
|
||||
opacity: 0.5;
|
||||
}
|
||||
100% {
|
||||
width: 100%;
|
||||
transform: translateX(0) scaleX(1);
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
16
components/radio/ButtonStyle.cs
Normal file
16
components/radio/ButtonStyle.cs
Normal file
@ -0,0 +1,16 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace AntDesign
|
||||
{
|
||||
public enum RadioButtonStyle
|
||||
{
|
||||
Outline,
|
||||
Solid
|
||||
}
|
||||
}
|
21
components/radio/EnumRadioGroup.cs
Normal file
21
components/radio/EnumRadioGroup.cs
Normal file
@ -0,0 +1,21 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace AntDesign
|
||||
{
|
||||
public class EnumRadioGroup<TEnum> : RadioGroup<TEnum>
|
||||
{
|
||||
public EnumRadioGroup()
|
||||
{
|
||||
Options = EnumHelper<TEnum>.GetValueLabelList()
|
||||
.Select(x => new RadioOption<TEnum> { Value = x.Value, Label = x.Label })
|
||||
.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
@ -3,9 +3,29 @@
|
||||
@inherits AntInputComponentBase<TValue>
|
||||
|
||||
<CascadingValue Value="this" IsFixed="@true">
|
||||
<CascadingValue Value="true" Name="InGroup" IsFixed>
|
||||
<div class="@ClassMapper.Class" style="@Style" id="@Id" @ref="Ref">
|
||||
@ChildContent
|
||||
</div>
|
||||
</CascadingValue>
|
||||
<CascadingValue Value="true" Name="InGroup" IsFixed>
|
||||
<div class="@ClassMapper.Class" style="@Style" id="@Id" @ref="Ref">
|
||||
@if (Options.Value != null)
|
||||
{
|
||||
if (Options.IsT0)
|
||||
{
|
||||
foreach (var item in Options.AsT0)
|
||||
{
|
||||
<Radio Value="@item">@item</Radio>
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@foreach (var radio in Options.AsT1)
|
||||
{
|
||||
<Radio TValue="TValue" Value="radio.Value" Disabled="radio.Disabled">@radio.Label</Radio>
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@ChildContent
|
||||
}
|
||||
</div>
|
||||
</CascadingValue>
|
||||
</CascadingValue>
|
@ -16,7 +16,7 @@ namespace AntDesign
|
||||
public bool Disabled { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public string ButtonStyle { get; set; } = "outline";
|
||||
public RadioButtonStyle ButtonStyle { get; set; } = RadioButtonStyle.Outline;
|
||||
|
||||
[Parameter]
|
||||
public string Name { get; set; }
|
||||
@ -35,6 +35,9 @@ namespace AntDesign
|
||||
[Parameter]
|
||||
public EventCallback<TValue> OnChange { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public OneOf<string[], RadioOption<TValue>[]> Options { get; set; }
|
||||
|
||||
private List<Radio<TValue>> _radioItems = new List<Radio<TValue>>();
|
||||
|
||||
private TValue _defaultValue;
|
||||
@ -42,13 +45,19 @@ namespace AntDesign
|
||||
private bool _hasDefaultValue;
|
||||
private bool _defaultValueSetted;
|
||||
|
||||
private static readonly Dictionary<RadioButtonStyle, string> _buttonStyleDics = new()
|
||||
{
|
||||
[RadioButtonStyle.Outline] = "outline",
|
||||
[RadioButtonStyle.Solid] = "solid",
|
||||
};
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
string prefixCls = "ant-radio-group";
|
||||
ClassMapper.Add(prefixCls)
|
||||
.If($"{prefixCls}-large", () => Size == "large")
|
||||
.If($"{prefixCls}-small", () => Size == "small")
|
||||
.GetIf(() => $"{prefixCls}-{ButtonStyle}", () => ButtonStyle.IsIn("outline", "solid"))
|
||||
.GetIf(() => $"{prefixCls}-{_buttonStyleDics[ButtonStyle]}", () => ButtonStyle.IsIn(RadioButtonStyle.Outline, RadioButtonStyle.Solid))
|
||||
.If($"{prefixCls}-rtl", () => RTL)
|
||||
;
|
||||
|
||||
|
19
components/radio/RadioOption.cs
Normal file
19
components/radio/RadioOption.cs
Normal file
@ -0,0 +1,19 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace AntDesign
|
||||
{
|
||||
public class RadioOption<TValue>
|
||||
{
|
||||
public string Label { get; set; }
|
||||
|
||||
public TValue Value { get; set; }
|
||||
|
||||
public bool Disabled { get; set; }
|
||||
}
|
||||
}
|
@ -13,7 +13,6 @@
|
||||
|
||||
display: inline-block;
|
||||
font-size: 0;
|
||||
line-height: unset;
|
||||
|
||||
.@{ant-prefix}-badge-count {
|
||||
z-index: 1;
|
||||
|
@ -33,16 +33,20 @@
|
||||
}
|
||||
|
||||
> div {
|
||||
transition: all 0.3s;
|
||||
transition: all 0.3s, outline 0s;
|
||||
|
||||
&:hover,
|
||||
&:focus-visible {
|
||||
transform: @rate-star-hover-scale;
|
||||
}
|
||||
|
||||
&:focus:not(:focus-visible) {
|
||||
&:focus {
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
&:focus-visible {
|
||||
outline: 1px dashed @rate-star-color;
|
||||
}
|
||||
}
|
||||
|
||||
&-first,
|
||||
|
@ -1,12 +1,12 @@
|
||||
@using AntDesign.Internal
|
||||
@using AntDesign.Select.Internal
|
||||
@namespace AntDesign
|
||||
@inherits AntInputComponentBase<TItemValue>
|
||||
@inherits SelectBase<TItemValue, TItem>
|
||||
@typeparam TItemValue
|
||||
@typeparam TItem
|
||||
|
||||
<CascadingValue Value="this" IsFixed="true">
|
||||
<CascadingValue Value=@("ant-select-dropdown") Name="PrefixCls">
|
||||
<CascadingValue Value="this" IsFixed>
|
||||
<CascadingValue Value=@("ant-select-dropdown") Name="PrefixCls" IsFixed>
|
||||
<div class="@ClassMapper.Class" style="@Style" id="@Id" tabindex="-1" @ref="Ref">
|
||||
<OverlayTrigger @ref="@_dropDown"
|
||||
Visible="Open"
|
||||
|
File diff suppressed because it is too large
Load Diff
883
components/select/SelectBase.cs
Normal file
883
components/select/SelectBase.cs
Normal file
@ -0,0 +1,883 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
#region using block
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Text.Json;
|
||||
using System.Threading.Tasks;
|
||||
using AntDesign.Internal;
|
||||
using AntDesign.Select;
|
||||
using AntDesign.Select.Internal;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.AspNetCore.Components.Web;
|
||||
using OneOf;
|
||||
|
||||
#endregion
|
||||
|
||||
namespace AntDesign
|
||||
{
|
||||
public abstract class SelectBase<TItemValue, TItem> : AntInputComponentBase<TItemValue>
|
||||
{
|
||||
protected const string DefaultWidth = "width: 100%;";
|
||||
|
||||
private SelectOptionItem<TItemValue, TItem> _activeOption;
|
||||
protected OverlayTrigger _dropDown;
|
||||
|
||||
internal ElementReference _dropDownRef;
|
||||
|
||||
internal ElementReference _inputRef;
|
||||
protected bool _isInitialized;
|
||||
|
||||
|
||||
protected bool _isPrimitive;
|
||||
|
||||
/// <summary>
|
||||
/// How long (number of characters) a tag will be.
|
||||
/// Only for Mode = "multiple" or Mode = "tags"
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The maximum length of the tag text.
|
||||
/// </value>
|
||||
private OneOf<int, ResponsiveTag> _maxTagCount;
|
||||
|
||||
protected int _maxTagCountAsInt;
|
||||
protected string _prevSearchValue = string.Empty;
|
||||
protected string _searchValue = string.Empty;
|
||||
|
||||
|
||||
protected SelectContent<TItemValue, TItem> _selectContent;
|
||||
|
||||
protected IEnumerable<TItemValue> _selectedValues;
|
||||
|
||||
protected Action<TItem, string> _setLabel;
|
||||
|
||||
protected Action<TItem, TItemValue> _setValue;
|
||||
/// <summary>
|
||||
/// Show clear button.
|
||||
/// </summary>
|
||||
[Parameter] public bool AllowClear { get; set; }
|
||||
/// <summary>
|
||||
/// Whether the current search will be cleared on selecting an item.
|
||||
/// </summary>
|
||||
[Parameter] public bool AutoClearSearchValue { get; set; } = true;
|
||||
/// <summary>
|
||||
/// Whether the Select component is disabled.
|
||||
/// </summary>
|
||||
[Parameter] public bool Disabled { get; set; }
|
||||
/// <summary>
|
||||
/// Set mode of Select - default | multiple | tags
|
||||
/// </summary>
|
||||
[Parameter] public string Mode { get; set; } = "default";
|
||||
/// <summary>
|
||||
/// Indicates whether the search function is active or not. Always true for mode tags.
|
||||
/// </summary>
|
||||
[Parameter] public bool EnableSearch { get; set; }
|
||||
/// <summary>
|
||||
/// Show loading indicator. You have to write the loading logic on your own.
|
||||
/// </summary>
|
||||
[Parameter] public bool Loading { get; set; }
|
||||
/// <summary>
|
||||
/// Controlled open state of dropdown.
|
||||
/// </summary>
|
||||
[Parameter] public bool Open { get; set; }
|
||||
/// <summary>
|
||||
/// Placeholder of select.
|
||||
/// </summary>
|
||||
[Parameter] public string Placeholder { get; set; }
|
||||
/// <summary>
|
||||
/// Called when focus.
|
||||
/// </summary>
|
||||
[Parameter] public Action OnFocus { get; set; }
|
||||
/// <summary>
|
||||
/// The name of the property to be used as a group indicator.
|
||||
/// If the value is set, the entries are displayed in groups.
|
||||
/// Use additional SortByGroup and SortByLabel.
|
||||
/// </summary>
|
||||
[Parameter] public SortDirection SortByGroup { get; set; } = SortDirection.None;
|
||||
/// <summary>
|
||||
/// Sort items by label value. None | Ascending | Descending
|
||||
/// </summary>
|
||||
[Parameter] public SortDirection SortByLabel { get; set; } = SortDirection.None;
|
||||
/// <summary>
|
||||
/// Hides the selected items when they are selected.
|
||||
/// </summary>
|
||||
[Parameter] public bool HideSelected { get; set; }
|
||||
/// <summary>
|
||||
/// Used for the two-way binding.
|
||||
/// </summary>
|
||||
[Parameter] public override EventCallback<TItemValue> ValueChanged { get; set; }
|
||||
/// <summary>
|
||||
/// Used for the two-way binding.
|
||||
/// </summary>
|
||||
[Parameter] public EventCallback<IEnumerable<TItemValue>> ValuesChanged { get; set; }
|
||||
/// <summary>
|
||||
/// The custom suffix icon.
|
||||
/// </summary>
|
||||
[Parameter] public RenderFragment SuffixIcon { get; set; }
|
||||
/// <summary>
|
||||
/// The custom prefix icon.
|
||||
/// </summary>
|
||||
[Parameter] public RenderFragment PrefixIcon { get; set; }
|
||||
|
||||
protected IEnumerable<TItemValue> _defaultValues;
|
||||
protected bool _defaultValuesHasItems;
|
||||
/// <summary>
|
||||
///
|
||||
/// Used when Mode = multiple | tags - The values are used during initialization and when pressing the Reset button within Forms.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public IEnumerable<TItemValue> DefaultValues
|
||||
{
|
||||
get => _defaultValues;
|
||||
set
|
||||
{
|
||||
if (value != null && _defaultValues != null)
|
||||
{
|
||||
var hasChanged = !value.SequenceEqual(_defaultValues);
|
||||
|
||||
if (!hasChanged)
|
||||
return;
|
||||
|
||||
_defaultValuesHasItems = value.Any();
|
||||
_defaultValues = value;
|
||||
}
|
||||
else if (value != null && _defaultValues == null)
|
||||
{
|
||||
_defaultValuesHasItems = value.Any();
|
||||
_defaultValues = value;
|
||||
}
|
||||
else if (value == null && _defaultValues != null)
|
||||
{
|
||||
_defaultValuesHasItems = false;
|
||||
_defaultValues = default;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when the user clears the selection.
|
||||
/// </summary>
|
||||
[Parameter] public Action OnClearSelected { get; set; }
|
||||
|
||||
internal bool IsResponsive { get; set; }
|
||||
|
||||
internal HashSet<SelectOptionItem<TItemValue, TItem>> SelectOptionItems { get; } = new();
|
||||
internal List<SelectOptionItem<TItemValue, TItem>> SelectedOptionItems { get; } = new();
|
||||
/// <summary>
|
||||
/// Called when the selected item changes.
|
||||
/// </summary>
|
||||
[Parameter] public Action<TItem> OnSelectedItemChanged { get; set; }
|
||||
/// <summary>
|
||||
/// Called when the selected items changes.
|
||||
/// </summary>
|
||||
[Parameter] public Action<IEnumerable<TItem>> OnSelectedItemsChanged { get; set; }
|
||||
|
||||
internal virtual SelectMode SelectMode => Mode.ToSelectMode();
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Currently active (highlighted) option.
|
||||
/// It does not have to be equal to selected option.
|
||||
/// </summary>
|
||||
internal SelectOptionItem<TItemValue, TItem> ActiveOption
|
||||
{
|
||||
get => _activeOption;
|
||||
set
|
||||
{
|
||||
if (_activeOption != value)
|
||||
{
|
||||
if (_activeOption != null && _activeOption.IsActive)
|
||||
{
|
||||
_activeOption.IsActive = false;
|
||||
}
|
||||
|
||||
_activeOption = value;
|
||||
if (_activeOption != null && !_activeOption.IsActive)
|
||||
{
|
||||
_activeOption.IsActive = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get or set the selected values.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public virtual IEnumerable<TItemValue> Values
|
||||
{
|
||||
get => _selectedValues;
|
||||
set
|
||||
{
|
||||
if (value != null && _selectedValues != null)
|
||||
{
|
||||
var hasChanged = !value.SequenceEqual(_selectedValues);
|
||||
|
||||
if (!hasChanged)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_selectedValues = value;
|
||||
_ = OnValuesChangeAsync(value);
|
||||
}
|
||||
else if (value != null && _selectedValues == null)
|
||||
{
|
||||
_selectedValues = value;
|
||||
|
||||
_ = OnValuesChangeAsync(value);
|
||||
}
|
||||
else if (value == null && _selectedValues != null)
|
||||
{
|
||||
_selectedValues = default;
|
||||
|
||||
_ = OnValuesChangeAsync(default);
|
||||
}
|
||||
|
||||
if (_isNotifyFieldChanged && Form?.ValidateOnChange == true)
|
||||
{
|
||||
EditContext?.NotifyFieldChanged(FieldIdentifier);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts custom tag (a string) to TItemValue type.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public Func<string, TItemValue> CustomTagLabelToValue { get; set; } =
|
||||
label => (TItemValue)TypeDescriptor.GetConverter(typeof(TItemValue)).ConvertFromInvariantString(label);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Determines if SelectOptions has any selected items
|
||||
/// </summary>
|
||||
/// <returns>true if SelectOptions has any selected Items, otherwise false</returns>
|
||||
internal bool HasValue => SelectOptionItems.Any(x => x.IsSelected);
|
||||
|
||||
/// <summary>
|
||||
/// Returns the value of EnableSearch parameter
|
||||
/// </summary>
|
||||
/// <returns>true if search is enabled</returns>
|
||||
internal bool IsSearchEnabled => EnableSearch;
|
||||
|
||||
/// <summary>
|
||||
/// Sorted list of SelectOptionItems
|
||||
/// </summary>
|
||||
protected internal IEnumerable<SelectOptionItem<TItemValue, TItem>> SortedSelectOptionItems
|
||||
{
|
||||
get
|
||||
{
|
||||
var selectOption = SelectOptionItems;
|
||||
|
||||
if (SortByGroup == SortDirection.Ascending && SortByLabel == SortDirection.None)
|
||||
{
|
||||
return selectOption.OrderBy(g => g.GroupName);
|
||||
}
|
||||
|
||||
if (SortByGroup == SortDirection.Descending && SortByLabel == SortDirection.None)
|
||||
{
|
||||
return selectOption.OrderByDescending(g => g.GroupName);
|
||||
}
|
||||
|
||||
if (SortByGroup == SortDirection.None && SortByLabel == SortDirection.Ascending)
|
||||
{
|
||||
return selectOption.OrderBy(l => l.Label);
|
||||
}
|
||||
|
||||
if (SortByGroup == SortDirection.None && SortByLabel == SortDirection.Descending)
|
||||
{
|
||||
return selectOption.OrderByDescending(l => l.Label);
|
||||
}
|
||||
|
||||
if (SortByGroup == SortDirection.Ascending && SortByLabel == SortDirection.Ascending)
|
||||
{
|
||||
return selectOption.OrderBy(g => g.GroupName).ThenBy(l => l.Label);
|
||||
}
|
||||
|
||||
if (SortByGroup == SortDirection.Ascending && SortByLabel == SortDirection.Descending)
|
||||
{
|
||||
return selectOption.OrderBy(g => g.GroupName).OrderByDescending(l => l.Label);
|
||||
}
|
||||
|
||||
if (SortByGroup == SortDirection.Descending && SortByLabel == SortDirection.Ascending)
|
||||
{
|
||||
return selectOption.OrderByDescending(g => g.GroupName).ThenBy(l => l.Label);
|
||||
}
|
||||
|
||||
if (SortByGroup == SortDirection.Descending && SortByLabel == SortDirection.Descending)
|
||||
{
|
||||
return selectOption.OrderByDescending(g => g.GroupName).OrderByDescending(l => l.Label);
|
||||
}
|
||||
|
||||
return selectOption;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used for rendering select options manually.
|
||||
/// </summary>
|
||||
[Parameter] public RenderFragment SelectOptions { get; set; }
|
||||
|
||||
|
||||
internal List<SelectOptionItem<TItemValue, TItem>> AddedTags { get; } = new();
|
||||
|
||||
internal SelectOptionItem<TItemValue, TItem> CustomTagSelectOptionItem { get; set; }
|
||||
|
||||
internal bool Focused { get; set; }
|
||||
internal bool HasTagCount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// How long (number of characters) a tag will be.
|
||||
/// Only for Mode = "multiple" or Mode = "tags"
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The maximum length of the tag text.
|
||||
/// </value>
|
||||
[Parameter] public int MaxTagTextLength { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether to embed label in value, turn the format of value from TItemValue to string (JSON)
|
||||
/// e.g. { "value": TItemValue, "label": "Label value" }
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public bool LabelInValue { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Max tag count to show. responsive will cost render performance.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public OneOf<int, ResponsiveTag> MaxTagCount
|
||||
{
|
||||
get => _maxTagCount;
|
||||
set
|
||||
{
|
||||
_maxTagCount = value;
|
||||
|
||||
value.Switch(intValue =>
|
||||
{
|
||||
IsResponsive = false;
|
||||
HasTagCount = intValue > 0;
|
||||
_maxTagCountAsInt = intValue;
|
||||
}, enumValue =>
|
||||
{
|
||||
IsResponsive = enumValue == ResponsiveTag.Responsive;
|
||||
HasTagCount = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a true/false if the placeholder should be displayed or not.
|
||||
/// </summary>
|
||||
/// <returns>true if SelectOptions has no values and the searchValue is empty; otherwise false </returns>
|
||||
protected bool ShowPlaceholder => !HasValue && string.IsNullOrEmpty(_searchValue);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The Method is called every time if the value of the @bind-Values was changed by the two-way binding.
|
||||
/// </summary>
|
||||
protected async Task OnValuesChangeAsync(IEnumerable<TItemValue> values)
|
||||
{
|
||||
if (
|
||||
!_isInitialized) // This is important because otherwise the initial value is overwritten by the EventCallback of ValueChanged and would be NULL.
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!SelectOptionItems.Any())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (values == null)
|
||||
{
|
||||
await ValuesChanged.InvokeAsync(default);
|
||||
OnSelectedItemsChanged?.Invoke(default);
|
||||
return;
|
||||
}
|
||||
|
||||
EvaluateValuesChangedOutsideComponent(values);
|
||||
|
||||
if (_dropDown.IsOverlayShow())
|
||||
{
|
||||
//A delay forces a refresh better than StateHasChanged().
|
||||
//For example when a tag is added that is causing SelectContent to grow,
|
||||
//this Task.Delay will actually allow to reposition the Overlay to match
|
||||
//new size of SelectContent.
|
||||
await Task.Delay(1);
|
||||
await UpdateOverlayPositionAsync();
|
||||
}
|
||||
|
||||
OnSelectedItemsChanged?.Invoke(SelectedOptionItems.Select(s => s.Item));
|
||||
await ValuesChanged.InvokeAsync(Values);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// When bind-Values is changed outside of the component, then component
|
||||
/// selected items have to be reselected according to new values passed.
|
||||
/// TODO: (Perf) Consider using hash to identify if the passed values are different from currently selected.
|
||||
/// </summary>
|
||||
/// <param name="values">The values that need to be selected.</param>
|
||||
private void EvaluateValuesChangedOutsideComponent(IEnumerable<TItemValue> values)
|
||||
{
|
||||
var newSelectedItems = new List<TItem>();
|
||||
var deselectList = SelectedOptionItems.ToDictionary(item => item.Value, item => item);
|
||||
foreach (var value in values.ToList())
|
||||
{
|
||||
SelectOptionItem<TItemValue, TItem> result;
|
||||
if (SelectMode == SelectMode.Multiple)
|
||||
{
|
||||
result = SelectOptionItems.FirstOrDefault(x =>
|
||||
!x.IsSelected && EqualityComparer<TItemValue>.Default.Equals(x.Value, value));
|
||||
if (result != null && !result.IsDisabled)
|
||||
{
|
||||
result.IsSelected = true;
|
||||
SelectedOptionItems.Add(result);
|
||||
}
|
||||
|
||||
deselectList.Remove(value);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = SelectOptionItems.FirstOrDefault(x =>
|
||||
EqualityComparer<TItemValue>.Default.Equals(x.Value, value));
|
||||
if (result is null) //tag delivered from outside, needs to be added to the list of options
|
||||
{
|
||||
result = CreateSelectOptionItem(value.ToString(), true);
|
||||
result.IsSelected = true;
|
||||
AddedTags.Add(result);
|
||||
SelectOptionItems.Add(result);
|
||||
SelectedOptionItems.Add(result);
|
||||
}
|
||||
else if (result != null && !result.IsSelected && !result.IsDisabled)
|
||||
{
|
||||
result.IsSelected = true;
|
||||
SelectedOptionItems.Add(result);
|
||||
}
|
||||
|
||||
deselectList.Remove(value);
|
||||
}
|
||||
}
|
||||
|
||||
if (deselectList.Count > 0)
|
||||
{
|
||||
foreach (var item in deselectList)
|
||||
{
|
||||
item.Value.IsSelected = false;
|
||||
SelectedOptionItems.Remove(item.Value);
|
||||
if (item.Value.IsAddedTag)
|
||||
{
|
||||
SelectOptionItems.Remove(item.Value);
|
||||
AddedTags.Remove(item.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates the select option item. Mostly meant to create new tags, that is why IsAddedTag is hardcoded to true.
|
||||
/// </summary>
|
||||
/// <param name="label">Creation based on passed label</param>
|
||||
/// <param name="isActive">if set to <c>true</c> [is active].</param>
|
||||
/// <returns></returns>
|
||||
protected SelectOptionItem<TItemValue, TItem> CreateSelectOptionItem(string label, bool isActive)
|
||||
{
|
||||
var value = CustomTagLabelToValue.Invoke(label);
|
||||
TItem item;
|
||||
if (_isPrimitive)
|
||||
{
|
||||
item = (TItem)TypeDescriptor.GetConverter(typeof(TItem)).ConvertFromInvariantString(_searchValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_setValue == null)
|
||||
{
|
||||
item = THelper.ChangeType<TItem>(value);
|
||||
}
|
||||
else
|
||||
{
|
||||
item = Activator.CreateInstance<TItem>();
|
||||
_setValue(item, value);
|
||||
}
|
||||
|
||||
_setLabel?.Invoke(item, _searchValue);
|
||||
}
|
||||
|
||||
return new SelectOptionItem<TItemValue, TItem>
|
||||
{
|
||||
Label = label,
|
||||
Value = value,
|
||||
Item = item,
|
||||
IsActive = isActive,
|
||||
IsSelected = false,
|
||||
IsAddedTag = true
|
||||
};
|
||||
}
|
||||
|
||||
internal bool IsDropdownShown()
|
||||
{
|
||||
return _dropDown.IsOverlayShow();
|
||||
}
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
SetClassMap();
|
||||
|
||||
if (string.IsNullOrWhiteSpace(Style))
|
||||
{
|
||||
Style = DefaultWidth;
|
||||
}
|
||||
|
||||
_isInitialized = true;
|
||||
|
||||
base.OnInitialized();
|
||||
}
|
||||
|
||||
protected void OnOverlayHide()
|
||||
{
|
||||
if (!IsSearchEnabled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!AutoClearSearchValue)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(_searchValue))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_searchValue = string.Empty;
|
||||
_prevSearchValue = string.Empty;
|
||||
|
||||
if (SelectMode != SelectMode.Default && HideSelected)
|
||||
{
|
||||
SelectOptionItems.Where(x => !x.IsSelected && x.IsHidden)
|
||||
.ForEach(i => i.IsHidden = false);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (CustomTagSelectOptionItem is not null)
|
||||
{
|
||||
SelectOptionItems.Remove(CustomTagSelectOptionItem);
|
||||
CustomTagSelectOptionItem = null;
|
||||
}
|
||||
|
||||
SelectOptionItems.Where(x => x.IsHidden)
|
||||
.ForEach(i => i.IsHidden = false);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A separate method to invoke ValuesChanged and OnSelectedItemsChanged to reduce code duplicates.
|
||||
/// </summary>
|
||||
protected void InvokeOnSelectedItemChanged(SelectOptionItem<TItemValue, TItem> selectOptionItem = null)
|
||||
{
|
||||
if (selectOptionItem == null)
|
||||
{
|
||||
OnSelectedItemsChanged?.Invoke(default);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (LabelInValue && SelectOptions != null)
|
||||
{
|
||||
// Embed the label into the value and return the result as json string.
|
||||
var valueLabel = new ValueLabel<TItemValue>
|
||||
{
|
||||
Value = selectOptionItem.Value, Label = selectOptionItem.Label
|
||||
};
|
||||
|
||||
var json = JsonSerializer.Serialize(valueLabel);
|
||||
|
||||
OnSelectedItemChanged?.Invoke((TItem)Convert.ChangeType(json, typeof(TItem)));
|
||||
}
|
||||
else
|
||||
{
|
||||
OnSelectedItemChanged?.Invoke(selectOptionItem.Item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The method is called every time if the user select/de-select a item by mouse or keyboard.
|
||||
/// Don't change the IsSelected property outside of this function.
|
||||
/// </summary>
|
||||
protected internal async Task SetValueAsync(SelectOptionItem<TItemValue, TItem> selectOption)
|
||||
{
|
||||
if (selectOption == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(selectOption));
|
||||
}
|
||||
|
||||
if (SelectMode == SelectMode.Default)
|
||||
{
|
||||
if (SelectedOptionItems.Count > 0)
|
||||
{
|
||||
SelectedOptionItems[0].IsSelected = false;
|
||||
SelectedOptionItems[0] = selectOption;
|
||||
}
|
||||
else
|
||||
{
|
||||
SelectedOptionItems.Add(selectOption);
|
||||
}
|
||||
|
||||
selectOption.IsSelected = true;
|
||||
await ValueChanged.InvokeAsync(selectOption.Value);
|
||||
InvokeOnSelectedItemChanged(selectOption);
|
||||
}
|
||||
else
|
||||
{
|
||||
selectOption.IsSelected = !selectOption.IsSelected;
|
||||
|
||||
if (selectOption.IsSelected)
|
||||
{
|
||||
if (HideSelected && !selectOption.IsHidden)
|
||||
{
|
||||
selectOption.IsHidden = true;
|
||||
}
|
||||
|
||||
if (IsSearchEnabled && !string.IsNullOrWhiteSpace(_searchValue))
|
||||
{
|
||||
ClearSearch();
|
||||
}
|
||||
|
||||
if (selectOption.IsAddedTag)
|
||||
{
|
||||
CustomTagSelectOptionItem = null;
|
||||
AddedTags.Add(selectOption);
|
||||
SelectOptionItems.Add(selectOption);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (selectOption.IsHidden)
|
||||
{
|
||||
selectOption.IsHidden = false;
|
||||
}
|
||||
|
||||
if (selectOption.IsAddedTag)
|
||||
{
|
||||
SelectOptionItems.Remove(selectOption);
|
||||
SelectedOptionItems.Remove(selectOption);
|
||||
if (selectOption.IsAddedTag && SelectOptions != null)
|
||||
{
|
||||
AddedTags.Remove(selectOption);
|
||||
}
|
||||
}
|
||||
|
||||
if (IsResponsive)
|
||||
{
|
||||
await _selectContent.RemovedItem();
|
||||
}
|
||||
}
|
||||
|
||||
if (EnableSearch || SelectMode == SelectMode.Tags)
|
||||
{
|
||||
await SetInputFocusAsync();
|
||||
}
|
||||
|
||||
await InvokeValuesChanged(selectOption);
|
||||
await UpdateOverlayPositionAsync();
|
||||
}
|
||||
}
|
||||
|
||||
protected async Task InvokeValuesChanged(SelectOptionItem<TItemValue, TItem> newSelection = null)
|
||||
{
|
||||
List<TItemValue> newSelectedValues;
|
||||
if (newSelection is null || Values is null)
|
||||
{
|
||||
newSelectedValues = new List<TItemValue>();
|
||||
SelectedOptionItems.Clear();
|
||||
SelectOptionItems.Where(x => x.IsSelected)
|
||||
.ForEach(i =>
|
||||
{
|
||||
newSelectedValues.Add(i.Value);
|
||||
SelectedOptionItems.Add(i);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
newSelectedValues = Values.ToList();
|
||||
if (newSelection.IsSelected)
|
||||
{
|
||||
newSelectedValues.Add(newSelection.Value);
|
||||
SelectedOptionItems.Add(newSelection);
|
||||
}
|
||||
else
|
||||
{
|
||||
newSelectedValues.Remove(newSelection.Value);
|
||||
SelectedOptionItems.Remove(newSelection);
|
||||
}
|
||||
}
|
||||
|
||||
if (ValuesChanged.HasDelegate)
|
||||
{
|
||||
await ValuesChanged.InvokeAsync(newSelectedValues);
|
||||
}
|
||||
else
|
||||
{
|
||||
Values = newSelectedValues;
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
|
||||
protected void ClearSearch()
|
||||
{
|
||||
if (SelectMode != SelectMode.Default)
|
||||
{
|
||||
foreach (var item in SelectOptionItems)
|
||||
{
|
||||
if (item.IsHidden)
|
||||
{
|
||||
if (HideSelected && !item.IsSelected || !HideSelected)
|
||||
{
|
||||
item.IsHidden = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var item in AddedTags)
|
||||
{
|
||||
if (item.IsHidden)
|
||||
{
|
||||
if (HideSelected && !item.IsSelected || !HideSelected)
|
||||
{
|
||||
item.IsHidden = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_searchValue = string.Empty;
|
||||
_prevSearchValue = string.Empty;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Method is called via EventCallBack after the user clicked on the Clear icon inside the Input element.
|
||||
/// Set the IsSelected and IsHidden properties for all items to False. It updates the overlay position if
|
||||
/// the SelectMode is Tags or Multiple. Invoke the OnClearSelected Action. Set the Value(s) to default.
|
||||
/// </summary>
|
||||
protected async Task OnInputClearClickAsync(MouseEventArgs _)
|
||||
{
|
||||
List<SelectOptionItem<TItemValue, TItem>> tagItems = new();
|
||||
|
||||
SelectOptionItems.Where(c => c.IsSelected)
|
||||
.ForEach(i =>
|
||||
{
|
||||
i.IsSelected = false;
|
||||
i.IsHidden = false;
|
||||
if (i.IsAddedTag)
|
||||
{
|
||||
tagItems.Add(i);
|
||||
}
|
||||
});
|
||||
//When clearing, also remove all added tags that are kept after adding in SelectOptionItems
|
||||
if (tagItems.Count > 0)
|
||||
{
|
||||
foreach (var item in tagItems)
|
||||
{
|
||||
SelectOptionItems.Remove(item);
|
||||
}
|
||||
}
|
||||
|
||||
AddedTags.Clear();
|
||||
ActiveOption = SelectOptionItems.FirstOrDefault();
|
||||
CustomTagSelectOptionItem = null;
|
||||
SelectedOptionItems.Clear();
|
||||
|
||||
await ClearSelectedAsync();
|
||||
|
||||
if (SelectMode != SelectMode.Default)
|
||||
{
|
||||
await Task.Delay(1); // Todo - Workaround because UI does not refresh
|
||||
await UpdateOverlayPositionAsync();
|
||||
StateHasChanged(); // Todo - Workaround because UI does not refresh
|
||||
}
|
||||
|
||||
OnClearSelected?.Invoke();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if Focused property is False; Set the Focused property to true, change the
|
||||
/// style and set the Focus on the Input element via DOM. It also invoke the OnFocus Action.
|
||||
/// </summary>
|
||||
protected async Task SetInputFocusAsync()
|
||||
{
|
||||
if (!Focused)
|
||||
{
|
||||
Focused = true;
|
||||
|
||||
SetClassMap();
|
||||
|
||||
await FocusAsync(_inputRef);
|
||||
|
||||
OnFocus?.Invoke();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Inform the Overlay to update the position.
|
||||
/// </summary>
|
||||
internal async Task UpdateOverlayPositionAsync()
|
||||
{
|
||||
if (_dropDown.Visible)
|
||||
{
|
||||
await _dropDown.GetOverlayComponent().UpdatePosition();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
internal async Task OnArrowClick(MouseEventArgs args)
|
||||
{
|
||||
await _dropDown.OnClickDiv(args);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Close the overlay
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
internal async Task CloseAsync()
|
||||
{
|
||||
await _dropDown.Hide(true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called by the Form reset method
|
||||
/// </summary>
|
||||
internal override void ResetValue()
|
||||
{
|
||||
_ = ClearSelectedAsync();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Clears the selectValue(s) property and send the null(default) value back through the two-way binding.
|
||||
/// </summary>
|
||||
protected async Task ClearSelectedAsync()
|
||||
{
|
||||
if (SelectMode == SelectMode.Default)
|
||||
{
|
||||
OnSelectedItemChanged?.Invoke(default);
|
||||
await ValueChanged.InvokeAsync(default);
|
||||
}
|
||||
else
|
||||
{
|
||||
OnSelectedItemsChanged?.Invoke(default);
|
||||
await ValuesChanged.InvokeAsync(default);
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract void SetClassMap();
|
||||
}
|
||||
}
|
@ -15,7 +15,7 @@ namespace AntDesign.Select.Internal
|
||||
{
|
||||
public partial class SelectContent<TItemValue, TItem> : IDisposable
|
||||
{
|
||||
[CascadingParameter(Name = "ParentSelect")] internal Select<TItemValue, TItem> ParentSelect { get; set; }
|
||||
[CascadingParameter(Name = "ParentSelect")] internal SelectBase<TItemValue, TItem> ParentSelect { get; set; }
|
||||
[CascadingParameter(Name = "ParentLabelTemplate")] internal RenderFragment<TItem> ParentLabelTemplate { get; set; }
|
||||
[CascadingParameter(Name = "ParentMaxTagPlaceholerTemplate")] internal RenderFragment<IEnumerable<TItem>> ParentMaxTagPlaceholerTemplate { get; set; }
|
||||
[CascadingParameter(Name = "ShowSearchIcon")] internal bool ShowSearchIcon { get; set; }
|
||||
@ -110,7 +110,7 @@ namespace AntDesign.Select.Internal
|
||||
{
|
||||
DomEventListener.AddShared<JsonElement>("window", "beforeunload", Reloading);
|
||||
await Js.InvokeVoidAsync(JSInteropConstants.AddPreventKeys, ParentSelect._inputRef, new[] { "ArrowUp", "ArrowDown" });
|
||||
await Js.InvokeVoidAsync(JSInteropConstants.AddPreventEnterOnOverlayVisible, ParentSelect._inputRef, ParentSelect.DropDownRef);
|
||||
await Js.InvokeVoidAsync(JSInteropConstants.AddPreventEnterOnOverlayVisible, ParentSelect._inputRef, ParentSelect._dropDownRef);
|
||||
}
|
||||
if (ParentSelect.IsResponsive)
|
||||
{
|
||||
|
@ -117,7 +117,7 @@
|
||||
&-arrow {
|
||||
.iconfont-mixin();
|
||||
position: absolute;
|
||||
top: 53%;
|
||||
top: 50%;
|
||||
right: @control-padding-horizontal - 1px;
|
||||
width: @font-size-sm;
|
||||
height: @font-size-sm;
|
||||
@ -199,21 +199,21 @@
|
||||
outline: none;
|
||||
box-shadow: @box-shadow-base;
|
||||
|
||||
&.slide-up-enter.slide-up-enter-active&-placement-bottomLeft,
|
||||
&.slide-up-appear.slide-up-appear-active&-placement-bottomLeft {
|
||||
&.@{ant-prefix}-slide-up-enter.@{ant-prefix}-slide-up-enter-active&-placement-bottomLeft,
|
||||
&.@{ant-prefix}-slide-up-appear.@{ant-prefix}-slide-up-appear-active&-placement-bottomLeft {
|
||||
animation-name: antSlideUpIn;
|
||||
}
|
||||
|
||||
&.slide-up-enter.slide-up-enter-active&-placement-topLeft,
|
||||
&.slide-up-appear.slide-up-appear-active&-placement-topLeft {
|
||||
&.@{ant-prefix}-slide-up-enter.@{ant-prefix}-slide-up-enter-active&-placement-topLeft,
|
||||
&.@{ant-prefix}-slide-up-appear.@{ant-prefix}-slide-up-appear-active&-placement-topLeft {
|
||||
animation-name: antSlideDownIn;
|
||||
}
|
||||
|
||||
&.slide-up-leave.slide-up-leave-active&-placement-bottomLeft {
|
||||
&.@{ant-prefix}-slide-up-leave.@{ant-prefix}-slide-up-leave-active&-placement-bottomLeft {
|
||||
animation-name: antSlideUpOut;
|
||||
}
|
||||
|
||||
&.slide-up-leave.slide-up-leave-active&-placement-topLeft {
|
||||
&.@{ant-prefix}-slide-up-leave.@{ant-prefix}-slide-up-leave-active&-placement-topLeft {
|
||||
animation-name: antSlideDownOut;
|
||||
}
|
||||
|
||||
@ -286,6 +286,9 @@
|
||||
}
|
||||
|
||||
&-disabled {
|
||||
&.@{select-prefix-cls}-item-option-selected {
|
||||
background-color: @select-multiple-disabled-background;
|
||||
}
|
||||
color: @disabled-color;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
@ -7,11 +7,4 @@
|
||||
input::-ms-reveal {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&,
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
box-sizing: border-box; // 1
|
||||
}
|
||||
}
|
||||
|
@ -3,8 +3,8 @@
|
||||
.modal-mask() {
|
||||
pointer-events: none;
|
||||
|
||||
&.zoom-enter,
|
||||
&.zoom-appear {
|
||||
&.@{ant-prefix}-zoom-enter,
|
||||
&.@{ant-prefix}zoom-appear {
|
||||
transform: none; // reset scale avoid mousePosition bug
|
||||
opacity: 0;
|
||||
animation-duration: @animation-duration-slow;
|
||||
|
@ -314,6 +314,7 @@
|
||||
@table-header-sort-bg: #262626;
|
||||
@table-header-filter-active-bg: #434343;
|
||||
@table-header-sort-active-bg: #303030;
|
||||
@table-fixed-header-sort-active-bg: #222;
|
||||
@table-filter-btns-bg: @popover-background;
|
||||
@table-expanded-row-bg: @table-header-bg;
|
||||
@table-filter-dropdown-bg: @popover-background;
|
||||
|
@ -149,6 +149,7 @@
|
||||
// Disabled states
|
||||
@disabled-color: fade(#000, 25%);
|
||||
@disabled-bg: @background-color-base;
|
||||
@disabled-active-bg: tint(@black, 90%);
|
||||
@disabled-color-dark: fade(#fff, 35%);
|
||||
|
||||
// Shadow
|
||||
@ -270,7 +271,7 @@
|
||||
@radio-button-color: @btn-default-color;
|
||||
@radio-button-hover-color: @primary-5;
|
||||
@radio-button-active-color: @primary-7;
|
||||
@radio-disabled-button-checked-bg: tint(@black, 90%);
|
||||
@radio-disabled-button-checked-bg: @disabled-active-bg;
|
||||
@radio-disabled-button-checked-color: @disabled-color;
|
||||
@radio-wrapper-margin-right: 8px;
|
||||
|
||||
@ -557,7 +558,8 @@
|
||||
@menu-item-vertical-margin: 4px;
|
||||
@menu-item-font-size: @font-size-base;
|
||||
@menu-item-boundary-margin: 8px;
|
||||
@menu-item-padding: 0 20px;
|
||||
@menu-item-padding-horizontal: 20px;
|
||||
@menu-item-padding: 0 @menu-item-padding-horizontal;
|
||||
@menu-horizontal-line-height: 46px;
|
||||
@menu-icon-margin-right: 10px;
|
||||
@menu-icon-size: @menu-item-font-size;
|
||||
@ -613,6 +615,8 @@
|
||||
// Sorter
|
||||
// Legacy: `table-header-sort-active-bg` is used for hover not real active
|
||||
@table-header-sort-active-bg: rgba(0, 0, 0, 0.04);
|
||||
@table-fixed-header-sort-active-bg: hsv(0, 0, 96%);
|
||||
|
||||
// Filter
|
||||
@table-header-filter-active-bg: rgba(0, 0, 0, 0.04);
|
||||
@table-filter-btns-bg: inherit;
|
||||
@ -636,7 +640,7 @@
|
||||
@picker-basic-cell-hover-color: @item-hover-bg;
|
||||
@picker-basic-cell-active-with-range-color: @primary-1;
|
||||
@picker-basic-cell-hover-with-range-color: lighten(@primary-color, 35%);
|
||||
@picker-basic-cell-disabled-bg: @disabled-bg;
|
||||
@picker-basic-cell-disabled-bg: rgba(0, 0, 0, 0.04);
|
||||
@picker-border-color: @border-color-split;
|
||||
@picker-date-hover-range-border-color: lighten(@primary-color, 20%);
|
||||
@picker-date-hover-range-color: @picker-basic-cell-hover-with-range-color;
|
||||
@ -796,8 +800,8 @@
|
||||
@pagination-font-weight-active: 500;
|
||||
@pagination-item-bg-active: @component-background;
|
||||
@pagination-item-link-bg: @component-background;
|
||||
@pagination-item-disabled-color-active: @white;
|
||||
@pagination-item-disabled-bg-active: darken(@disabled-bg, 10%);
|
||||
@pagination-item-disabled-color-active: @disabled-color;
|
||||
@pagination-item-disabled-bg-active: @disabled-active-bg;
|
||||
@pagination-item-input-bg: @component-background;
|
||||
@pagination-mini-options-size-changer-top: 0px;
|
||||
|
||||
|
@ -62,7 +62,7 @@ else if (!IsHeader && RowSpan != 0 && ColSpan != 0)
|
||||
</td>
|
||||
}
|
||||
|
||||
<td class="@ClassMapper.Class" style="@FixedStyle @Style" rowspan="@RowSpan" colspan="@ColSpan">
|
||||
<td class="@ClassMapper.Class" style="@FixedStyle @Style" rowspan="@RowSpan" colspan="@ColSpan" data-label="@Context.HeaderColumns[ColIndex].Title">
|
||||
@if (ColIndex == Table.TreeExpandIconColumnIndex && Table.TreeMode)
|
||||
{
|
||||
<span class="ant-table-row-indent indent-level-@RowData.Level" style="padding-left: @((CssSizeLength)(RowData.Level * Table.IndentSize));"></span>
|
||||
|
@ -41,6 +41,8 @@ namespace AntDesign
|
||||
|
||||
private TData _field;
|
||||
|
||||
public override string Title { get => base.Title ?? DisplayName ?? FieldName; set => base.Title = value; }
|
||||
|
||||
[Parameter]
|
||||
public string DataIndex { get; set; }
|
||||
|
||||
@ -120,7 +122,7 @@ namespace AntDesign
|
||||
|
||||
private Type _columnDataType;
|
||||
|
||||
public string? DisplayName { get; private set; }
|
||||
public string DisplayName { get; private set; }
|
||||
|
||||
public string FieldName { get; private set; }
|
||||
|
||||
@ -151,8 +153,6 @@ namespace AntDesign
|
||||
|
||||
private string[] _selectedFilterValues;
|
||||
|
||||
//private ElementReference _filterTriggerRef;
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
base.OnInitialized();
|
||||
|
@ -38,7 +38,7 @@ namespace AntDesign
|
||||
public bool IsSummary { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public string Title { get; set; }
|
||||
public virtual string Title { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public RenderFragment TitleTemplate { get; set; }
|
||||
|
@ -132,6 +132,9 @@ namespace AntDesign
|
||||
}
|
||||
}
|
||||
|
||||
[Parameter]
|
||||
public bool Responsive { get; set; } = true;
|
||||
|
||||
[Inject]
|
||||
private IDomEventListener DomEventListener { get; set; }
|
||||
|
||||
@ -151,7 +154,7 @@ namespace AntDesign
|
||||
private bool _hasFixLeft;
|
||||
private bool _hasFixRight;
|
||||
private int _treeExpandIconColumnIndex;
|
||||
private ClassMapper _wrapperClassMapper = new ClassMapper();
|
||||
private readonly ClassMapper _wrapperClassMapper = new ClassMapper();
|
||||
private string TableLayoutStyle => TableLayout == null ? "" : $"table-layout: {TableLayout};";
|
||||
|
||||
private ElementReference _tableHeaderRef;
|
||||
@ -329,6 +332,7 @@ namespace AntDesign
|
||||
|
||||
_wrapperClassMapper
|
||||
.Add($"{prefixCls}-wrapper")
|
||||
.If($"{prefixCls}-responsive", () => Responsive) // Not implemented in ant design
|
||||
.If($"{prefixCls}-wrapper-rtl", () => RTL);
|
||||
}
|
||||
|
||||
|
@ -12,13 +12,12 @@
|
||||
|
||||
> .@{table-prefix-cls}-container {
|
||||
// ============================ Content ============================
|
||||
border: @table-border;
|
||||
border-right: 0;
|
||||
border-bottom: 0;
|
||||
border-left: @table-border;
|
||||
|
||||
> .@{table-prefix-cls}-content,
|
||||
> .@{table-prefix-cls}-header,
|
||||
> .@{table-prefix-cls}-body {
|
||||
> .@{table-prefix-cls}-body,
|
||||
> .@{table-prefix-cls}-summary {
|
||||
> table {
|
||||
// ============================= Cell =============================
|
||||
> thead > tr > th,
|
||||
@ -66,6 +65,13 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
> .@{table-prefix-cls}-content,
|
||||
> .@{table-prefix-cls}-header {
|
||||
> table {
|
||||
border-top: @table-border;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.@{table-prefix-cls}-scroll-horizontal {
|
||||
|
@ -1 +1,2 @@
|
||||
@import './index.less';
|
||||
@import './patch.less';
|
@ -60,6 +60,12 @@
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
}
|
||||
|
||||
.@{table-prefix-cls}-column-title {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
word-break: keep-all;
|
||||
}
|
||||
}
|
||||
|
||||
// ============================ Title =============================
|
||||
@ -160,6 +166,8 @@
|
||||
|
||||
// =========================== Summary ============================
|
||||
&-summary {
|
||||
position: relative;
|
||||
z-index: @zindex-table-fixed;
|
||||
background: @table-bg;
|
||||
|
||||
div& {
|
||||
@ -217,6 +225,12 @@
|
||||
background-color: transparent !important;
|
||||
}
|
||||
}
|
||||
|
||||
// https://github.com/ant-design/ant-design/issues/30969
|
||||
&.@{table-prefix-cls}-cell-fix-left:hover,
|
||||
&.@{table-prefix-cls}-cell-fix-right:hover {
|
||||
background: @table-fixed-header-sort-active-bg;
|
||||
}
|
||||
}
|
||||
|
||||
&-thead th.@{table-prefix-cls}-column-sort {
|
||||
@ -231,6 +245,12 @@
|
||||
background: @table-body-sort-bg;
|
||||
}
|
||||
|
||||
&-column-title {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
&-column-sorters {
|
||||
display: flex;
|
||||
flex: auto;
|
||||
@ -623,7 +643,9 @@
|
||||
&-holder {
|
||||
position: sticky;
|
||||
z-index: @table-sticky-zindex;
|
||||
background: @component-background;
|
||||
}
|
||||
|
||||
&-scroll {
|
||||
position: sticky;
|
||||
bottom: 0;
|
||||
|
53
components/table/style/patch.less
Normal file
53
components/table/style/patch.less
Normal file
@ -0,0 +1,53 @@
|
||||
@import './index.less';
|
||||
|
||||
.@{table-prefix-cls}-responsive {
|
||||
|
||||
@media (max-width: 960px) {
|
||||
.@{table-prefix-cls} {
|
||||
table {
|
||||
table-layout: auto !important;
|
||||
width: 100% !important;
|
||||
|
||||
col {
|
||||
width: auto !important;
|
||||
min-width: auto !important;
|
||||
}
|
||||
}
|
||||
|
||||
&-thead {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&.@{table-prefix-cls}-fixed-column {
|
||||
.@{table-prefix-cls}-content {
|
||||
overflow: hidden !important;
|
||||
}
|
||||
}
|
||||
|
||||
&.@{table-prefix-cls}-scroll-horizontal {
|
||||
.@{table-prefix-cls}-body {
|
||||
overflow-x: hidden !important;
|
||||
}
|
||||
}
|
||||
|
||||
&-tbody {
|
||||
.@{table-prefix-cls}-cell {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
&:not(:last-child) {
|
||||
border: none;
|
||||
}
|
||||
}
|
||||
|
||||
.@{table-prefix-cls}-cell:before {
|
||||
content: attr(data-label);
|
||||
font-weight: 500;
|
||||
padding-right: 16px;
|
||||
padding-inline-end: 16px;
|
||||
padding-inline-start: unset;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -81,6 +81,7 @@
|
||||
|
||||
.@{tab-prefix-cls}-nav-add {
|
||||
min-width: @tabs-card-height;
|
||||
margin-left: @tabs-card-gutter;
|
||||
padding: 0 @padding-xs;
|
||||
background: @tabs-card-head-background;
|
||||
border: @border-width-base @border-style-base @border-color-split;
|
||||
|
@ -58,8 +58,14 @@
|
||||
> div > .@{tab-prefix-cls}-nav {
|
||||
.@{tab-prefix-cls}-tab + .@{tab-prefix-cls}-tab {
|
||||
.@{tab-prefix-cls}-rtl& {
|
||||
margin-right: 0;
|
||||
margin-left: @tabs-card-gutter;
|
||||
margin-right: @tabs-card-gutter;
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
.@{tab-prefix-cls}-nav-add {
|
||||
.@{tab-prefix-cls}-rtl& {
|
||||
margin-right: @tabs-card-gutter;
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,13 +1,17 @@
|
||||
@namespace AntDesign
|
||||
@inherits AntDomComponentBase
|
||||
|
||||
<CascadingValue Value="this" IsFixed="@true">
|
||||
<CascadingValue Value="this" IsFixed>
|
||||
<ul class="@ClassMapper.Class" style="@Style" id="@Id" @ref="Ref">
|
||||
@ChildContent
|
||||
|
||||
@foreach (var item in _displayItems)
|
||||
{
|
||||
<li class="@item.ItemClass" @ref="item.Ref" style="@item.Style" id="@item.Id">
|
||||
@if (!string.IsNullOrEmpty(item.Label))
|
||||
{
|
||||
<div class="ant-timeline-item-label">@item.Label</div>
|
||||
}
|
||||
<div class="ant-timeline-item-tail"></div>
|
||||
<div class="@item._headClassMapper.Class" style="@item.HeadStyle">
|
||||
@if (item.Dot != null)
|
||||
|
@ -12,7 +12,7 @@ namespace AntDesign
|
||||
/// 'left' | 'alternate' | 'right'
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public string Mode
|
||||
public TimelineMode? Mode
|
||||
{
|
||||
get => _mode;
|
||||
set
|
||||
@ -51,19 +51,20 @@ namespace AntDesign
|
||||
|
||||
_pendingItem = _pending.Value == null ? null : new TimelineItem()
|
||||
{
|
||||
Dot = PendingDot ?? _loadingDot,
|
||||
Class = "ant-timeline-item-pending"
|
||||
};
|
||||
|
||||
_pendingItem?.SetDot(PendingDot ?? _loadingDot);
|
||||
|
||||
_pending.Switch(str =>
|
||||
{
|
||||
_pendingItem.ChildContent = b =>
|
||||
{
|
||||
b.AddContent(0, str);
|
||||
};
|
||||
_pendingItem.SetChildContent(b =>
|
||||
{
|
||||
b.AddContent(0, str);
|
||||
});
|
||||
}, rf =>
|
||||
{
|
||||
_pendingItem.ChildContent = rf;
|
||||
_pendingItem.SetChildContent(rf);
|
||||
});
|
||||
|
||||
_pendingItem?.SetClassMap();
|
||||
@ -91,11 +92,11 @@ namespace AntDesign
|
||||
|
||||
protected IList<TimelineItem> _displayItems = new List<TimelineItem>();
|
||||
|
||||
private readonly bool _isPendingBoolean = false;
|
||||
private OneOf<string, RenderFragment> _pending;
|
||||
private bool _reverse;
|
||||
private bool _waitingItemUpdate = false;
|
||||
private string _mode;
|
||||
private TimelineMode? _mode;
|
||||
private bool _hasLabel;
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
@ -126,10 +127,11 @@ namespace AntDesign
|
||||
var prefix = "ant-timeline";
|
||||
ClassMapper.Clear()
|
||||
.Add(prefix)
|
||||
.If($"{prefix}-right", () => Mode == "right")
|
||||
.If($"{prefix}-alternate", () => Mode == "alternate")
|
||||
.If($"{prefix}-right", () => Mode == TimelineMode.Right && !_hasLabel)
|
||||
.If($"{prefix}-alternate", () => Mode == TimelineMode.Alternate && !_hasLabel)
|
||||
.If($"{prefix}-pending", () => Pending.Value != null)
|
||||
.If($"{prefix}-reverse", () => Reverse)
|
||||
.If($"{prefix}-label", () => _hasLabel)
|
||||
.If($"{prefix}-rtl", () => RTL);
|
||||
}
|
||||
|
||||
@ -143,6 +145,10 @@ namespace AntDesign
|
||||
{
|
||||
this._items.Add(item);
|
||||
_waitingItemUpdate = true;
|
||||
if (!string.IsNullOrEmpty(item.Label))
|
||||
{
|
||||
_hasLabel = true;
|
||||
}
|
||||
}
|
||||
|
||||
protected IEnumerable<TimelineItem> UpdateChildren(IEnumerable<TimelineItem> items)
|
||||
@ -155,11 +161,13 @@ namespace AntDesign
|
||||
{
|
||||
var item = items.ElementAt(i);
|
||||
item.IsLast = i == length - 1;
|
||||
item.Position =
|
||||
this.Mode == "left" || Mode == null ? null
|
||||
: this.Mode == "right" ? "right"
|
||||
: this.Mode == "alternate" && i % 2 == 0 ? "left"
|
||||
: "right";
|
||||
item.Position = _mode switch
|
||||
{
|
||||
TimelineMode.Left => "left",
|
||||
TimelineMode.Right => "right",
|
||||
TimelineMode.Alternate => i % 2 == 0 ? "left" : "right",
|
||||
_ => null,
|
||||
};
|
||||
|
||||
item.SetClassMap();
|
||||
|
||||
|
@ -14,6 +14,9 @@ namespace AntDesign
|
||||
[Parameter]
|
||||
public string Color { get; set; } = "blue";
|
||||
|
||||
[Parameter]
|
||||
public string Label { get; set; }
|
||||
|
||||
[CascadingParameter]
|
||||
public Timeline ParentTimeline { get; set; }
|
||||
|
||||
@ -68,5 +71,15 @@ namespace AntDesign
|
||||
.If($"{headPrefix}-{Color}", () => _defaultColors.Contains(Color))
|
||||
.If($"{headPrefix}-custom", () => Dot != null);
|
||||
}
|
||||
|
||||
internal void SetChildContent(RenderFragment childContent)
|
||||
{
|
||||
this.ChildContent = childContent;
|
||||
}
|
||||
|
||||
internal void SetDot(RenderFragment dot)
|
||||
{
|
||||
this.Dot = dot;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
17
components/timeline/TimelineMode.cs
Normal file
17
components/timeline/TimelineMode.cs
Normal file
@ -0,0 +1,17 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace AntDesign
|
||||
{
|
||||
public enum TimelineMode
|
||||
{
|
||||
Left,
|
||||
Right,
|
||||
Alternate
|
||||
}
|
||||
}
|
@ -18,6 +18,7 @@
|
||||
position: absolute;
|
||||
z-index: @zindex-tooltip;
|
||||
display: block;
|
||||
width: max-content;
|
||||
max-width: @tooltip-max-width;
|
||||
visibility: visible;
|
||||
|
||||
|
@ -17,6 +17,11 @@
|
||||
border: 0;
|
||||
border-radius: 0;
|
||||
|
||||
.@{table-prefix-cls}-selection-column {
|
||||
width: 40px;
|
||||
min-width: 40px;
|
||||
}
|
||||
|
||||
> .@{table-prefix-cls}-content {
|
||||
// Header background color
|
||||
> .@{table-prefix-cls}-body > table > .@{table-prefix-cls}-thead > tr > th {
|
||||
|
45
components/tree-select/SimpleTreeSelect.cs
Normal file
45
components/tree-select/SimpleTreeSelect.cs
Normal file
@ -0,0 +1,45 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
|
||||
namespace AntDesign
|
||||
{
|
||||
public class SimpleTreeSelect<TItem> : TreeSelect<TItem> where TItem : class
|
||||
{
|
||||
|
||||
|
||||
protected IEnumerable<TItem> RootData => ChildrenMethodExpression?.Invoke(RootValue);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Specifies a method to return a child node
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public Func<string, IList<TItem>> ChildrenMethodExpression { get; set; }
|
||||
|
||||
protected override Func<TreeNode<TItem>, IList<TItem>> TreeNodeChildrenExpression => node => ChildrenMethodExpression(TreeNodeKeyExpression(node));
|
||||
|
||||
|
||||
protected override Dictionary<string, object> TreeAttributes
|
||||
{
|
||||
get
|
||||
{
|
||||
return new()
|
||||
{
|
||||
{ "DataSource", RootData },
|
||||
{ "TitleExpression", TreeNodeTitleExpression },
|
||||
{ "DefaultExpandAll", TreeDefaultExpandAll },
|
||||
{ "KeyExpression", TreeNodeKeyExpression },
|
||||
{ "ChildrenExpression", TreeNodeChildrenExpression },
|
||||
{ "DisabledExpression", TreeNodeDisabledExpression },
|
||||
{ "IsLeafExpression", TreeNodeIsLeafExpression }
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
77
components/tree-select/TreeSelect.razor
Normal file
77
components/tree-select/TreeSelect.razor
Normal file
@ -0,0 +1,77 @@
|
||||
@namespace AntDesign
|
||||
@inherits SelectBase<string, TItem>
|
||||
@typeparam TItem
|
||||
|
||||
@using AntDesign.Internal
|
||||
@using AntDesign.Select.Internal
|
||||
|
||||
<CascadingValue Value="this" IsFixed>
|
||||
<CascadingValue Value=@("ant-select-dropdown") Name="PrefixCls" IsFixed>
|
||||
<div class="@ClassMapper.Class" style="@Style" id="@Id" tabindex="-1" @ref="Ref">
|
||||
<OverlayTrigger @ref="@_dropDown"
|
||||
Visible="Open"
|
||||
Disabled="Disabled"
|
||||
Trigger="new[] { Trigger.Click }"
|
||||
HiddenMode
|
||||
OnMouseEnter="@(() => { OnMouseEnter?.Invoke(); })"
|
||||
OnMouseLeave="@(() => { OnMouseLeave?.Invoke(); })"
|
||||
OnVisibleChange="@OnOverlayVisibleChangeAsync"
|
||||
PopupContainerSelector="@PopupContainerSelector"
|
||||
OverlayEnterCls="ant-slide-up-enter ant-slide-up-enter-active ant-slide-up"
|
||||
OverlayLeaveCls="ant-slide-up-leave ant-slide-up-leave-active ant-slide-up">
|
||||
<Overlay >
|
||||
<div style="@_dropdownStyle">
|
||||
<div class="" style="max-height: @PopupContainerMaxHeight; overflow-y: auto;">
|
||||
<div>
|
||||
<div class="" role="listbox" style="display: flex; flex-direction: column;">
|
||||
|
||||
<Tree TItem="TItem"
|
||||
BlockNode @ref="_tree" Multiple="Multiple"
|
||||
@attributes="TreeAttributes"
|
||||
SelectedKeys="SelectedKeys"
|
||||
OnClick="OnTreeNodeClick"
|
||||
OnUnSelect="OnTreeNodeUnSelect">
|
||||
<Nodes>
|
||||
@if (IsInnerModel)
|
||||
{
|
||||
<CascadingValue Name="Tree" Value="_tree" IsFixed="true">
|
||||
@ChildContent
|
||||
</CascadingValue>
|
||||
}
|
||||
</Nodes>
|
||||
|
||||
</Tree>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Overlay>
|
||||
<Unbound>
|
||||
<CascadingValue Value="this" Name=@("ParentSelect") IsFixed>
|
||||
<CascadingValue Value="@LabelTemplate" Name="ParentLabelTemplate">
|
||||
<CascadingValue Value="@ShowSearchIcon" Name="ShowSearchIcon">
|
||||
<CascadingValue Value="@ShowArrowIcon" Name="ShowArrowIcon">
|
||||
<SelectContent Prefix="ant-select"
|
||||
RefBack="@context"
|
||||
TItemValue="string"
|
||||
TItem="TItem"
|
||||
SearchValue="@_searchValue"
|
||||
IsOverlayShow="@_dropDown.IsOverlayShow()"
|
||||
OnInput="@OnInputAsync"
|
||||
OnKeyUp="@OnKeyUpAsync"
|
||||
OnKeyDown="@OnKeyDownAsync"
|
||||
OnFocus="@OnInputFocusAsync"
|
||||
OnBlur="@OnInputBlurAsync"
|
||||
OnClearClick="@OnInputClearClickAsync"
|
||||
OnRemoveSelected="@OnRemoveSelectedAsync"
|
||||
Placeholder="@Placeholder"
|
||||
ShowPlaceholder="@ShowPlaceholder" />
|
||||
</CascadingValue>
|
||||
</CascadingValue>
|
||||
</CascadingValue>
|
||||
</CascadingValue>
|
||||
</Unbound>
|
||||
</OverlayTrigger>
|
||||
</div>
|
||||
</CascadingValue>
|
||||
</CascadingValue>
|
466
components/tree-select/TreeSelect.razor.cs
Normal file
466
components/tree-select/TreeSelect.razor.cs
Normal file
@ -0,0 +1,466 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using AntDesign.Internal;
|
||||
using AntDesign.Select.Internal;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.AspNetCore.Components.Web;
|
||||
using AntDesign.Core.Helpers.MemberPath;
|
||||
using AntDesign.JsInterop;
|
||||
using OneOf;
|
||||
using System.Linq;
|
||||
|
||||
namespace AntDesign
|
||||
{
|
||||
public partial class TreeSelect<TItem> : SelectBase<string, TItem> where TItem : class
|
||||
{
|
||||
[Parameter] public bool ShowExpand { get; set; } = true;
|
||||
|
||||
protected Tree<TItem> _tree;
|
||||
|
||||
[Parameter]
|
||||
public bool Multiple
|
||||
{
|
||||
get => _multiple;
|
||||
set
|
||||
{
|
||||
_multiple = value;
|
||||
if (_multiple)
|
||||
{
|
||||
Mode = SelectMode.Multiple.ToString("G");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Parameter] public bool TreeCheckable { get; set; }
|
||||
|
||||
[Parameter] public string PopupContainerSelector { get; set; } = "body";
|
||||
|
||||
[Parameter] public Action OnMouseEnter { get; set; }
|
||||
|
||||
[Parameter] public Action OnMouseLeave { get; set; }
|
||||
|
||||
[Parameter] public RenderFragment<TItem> LabelTemplate { get; set; }
|
||||
|
||||
[Parameter] public bool ShowSearchIcon { get; set; } = true;
|
||||
|
||||
[Parameter] public bool ShowArrowIcon { get; set; } = true;
|
||||
|
||||
[Parameter] public TreeNode<TItem>[] Nodes { get; set; }
|
||||
|
||||
[Parameter] public IEnumerable<TItem> DataSource { get; set; }
|
||||
|
||||
[Parameter] public RenderFragment ChildContent { get; set; }
|
||||
|
||||
[Parameter] public bool TreeDefaultExpandAll { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public Func<IEnumerable<TItem>, string, TItem> DataItemExpression { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public Func<IList<TItem>, IEnumerable<string>, IEnumerable<TItem>> DataItemsExpression { get; set; }
|
||||
|
||||
[Parameter]
|
||||
|
||||
public string RootValue { get; set; } = "0";
|
||||
|
||||
protected Func<TreeNode<TItem>, string> TreeNodeTitleExpression
|
||||
{
|
||||
get
|
||||
{
|
||||
return node => TitleExpression(node.DataItem);
|
||||
}
|
||||
}
|
||||
|
||||
[Parameter]
|
||||
public Func<TItem, string> TitleExpression { get; set; }
|
||||
|
||||
|
||||
protected virtual Dictionary<string, object> TreeAttributes
|
||||
{
|
||||
get
|
||||
{
|
||||
return new()
|
||||
{
|
||||
{ "DataSource", DataSource },
|
||||
{ "TitleExpression", DataSource == null ? null : TreeNodeTitleExpression },
|
||||
{ "DefaultExpandAll", TreeDefaultExpandAll },
|
||||
{ "KeyExpression", DataSource == null ? null : TreeNodeKeyExpression },
|
||||
{ "ChildrenExpression", DataSource == null ? null : TreeNodeChildrenExpression },
|
||||
{ "DisabledExpression", DataSource == null ? null : TreeNodeDisabledExpression },
|
||||
{ "IsLeafExpression", DataSource == null ? null : TreeNodeIsLeafExpression }
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected Func<TreeNode<TItem>, string> TreeNodeKeyExpression
|
||||
{
|
||||
get
|
||||
{
|
||||
return node => KeyExpression(node.DataItem);
|
||||
}
|
||||
}
|
||||
|
||||
[Parameter]
|
||||
public Func<TItem, string> KeyExpression { get; set; }
|
||||
|
||||
|
||||
protected Func<TreeNode<TItem>, string> TreeNodeIconExpression
|
||||
{
|
||||
get
|
||||
{
|
||||
return node => IconExpression(node.DataItem);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Specifies a method to return the node icon.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public Func<TItem, string> IconExpression { get; set; }
|
||||
|
||||
protected Func<TreeNode<TItem>, bool> TreeNodeIsLeafExpression
|
||||
{
|
||||
get
|
||||
{
|
||||
return node => IsLeafExpression(node.DataItem);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private bool IsInnerModel => ChildContent != null;
|
||||
|
||||
/// <summary>
|
||||
/// Specifies a method that returns whether the expression is a leaf node.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public Func<TItem, bool> IsLeafExpression { get; set; }
|
||||
|
||||
|
||||
protected virtual Func<TreeNode<TItem>, IList<TItem>> TreeNodeChildrenExpression
|
||||
{
|
||||
get
|
||||
{
|
||||
return node => ChildrenExpression == null ? null : ChildrenExpression(node.DataItem);
|
||||
}
|
||||
}
|
||||
|
||||
[Parameter]
|
||||
public virtual Func<TItem, IList<TItem>> ChildrenExpression { get; set; }
|
||||
|
||||
protected Func<TreeNode<TItem>, bool> TreeNodeDisabledExpression
|
||||
{
|
||||
get
|
||||
{
|
||||
return node => DisabledExpression != null && DisabledExpression(node.DataItem);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Specifies a method to return a disabled node
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public Func<TItem, bool> DisabledExpression { get; set; }
|
||||
|
||||
[Parameter] public OneOf<bool, string> DropdownMatchSelectWidth { get; set; } = true;
|
||||
[Parameter] public string DropdownMaxWidth { get; set; } = "auto";
|
||||
|
||||
[Parameter] public string PopupContainerMaxHeight { get; set; } = "256px";
|
||||
|
||||
|
||||
|
||||
private bool IsMultiple => Multiple || TreeCheckable;
|
||||
|
||||
internal override SelectMode SelectMode => IsMultiple ? SelectMode.Multiple : base.SelectMode;
|
||||
|
||||
private string[] SelectedKeys => Values?.ToArray();
|
||||
//private readonly IList<TreeNode<TItem>> _selectedNodes = new List<TreeNode<TItem>>();
|
||||
|
||||
private string _dropdownStyle = string.Empty;
|
||||
private bool _multiple;
|
||||
private readonly string _dir = "ltr";
|
||||
|
||||
|
||||
|
||||
|
||||
public override string Value
|
||||
{
|
||||
get => base.Value;
|
||||
set
|
||||
{
|
||||
if (string.IsNullOrEmpty(value))
|
||||
return;
|
||||
if (base.Value == value)
|
||||
return;
|
||||
base.Value = value;
|
||||
|
||||
if (SelectOptionItems.Any(o => o.Value == value))
|
||||
{
|
||||
_ = SetValueAsync(SelectOptionItems.First(o => o.Value == value));
|
||||
}
|
||||
else
|
||||
{
|
||||
var data = DataItemExpression?.Invoke(DataSource, value);
|
||||
if (data != null)
|
||||
{
|
||||
var o = CreateOption(data, true);
|
||||
_ = SetValueAsync(o);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public override IEnumerable<string> Values
|
||||
{
|
||||
get => base.Values;
|
||||
set
|
||||
{
|
||||
if (!_isInitialized)
|
||||
return;
|
||||
|
||||
if (!Multiple)
|
||||
throw new NotImplementedException("not Multiple select, no die");
|
||||
|
||||
if (value != null && _selectedValues != null)
|
||||
{
|
||||
var hasChanged = !value.SequenceEqual(_selectedValues);
|
||||
|
||||
if (!hasChanged)
|
||||
return;
|
||||
|
||||
ClearOptions();
|
||||
|
||||
_selectedValues = value;
|
||||
CreateOptions(value);
|
||||
_ = OnValuesChangeAsync(value);
|
||||
}
|
||||
else if (value != null && _selectedValues == null)
|
||||
{
|
||||
_selectedValues = value;
|
||||
CreateOptions(value);
|
||||
_ = OnValuesChangeAsync(value);
|
||||
}
|
||||
else if (value == null && _selectedValues != null)
|
||||
{
|
||||
_selectedValues = default;
|
||||
|
||||
ClearOptions();
|
||||
|
||||
_ = OnValuesChangeAsync(default);
|
||||
}
|
||||
if (_isNotifyFieldChanged && (Form?.ValidateOnChange == true))
|
||||
{
|
||||
EditContext?.NotifyFieldChanged(FieldIdentifier);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private void ClearOptions()
|
||||
{
|
||||
SelectOptionItems.Clear();
|
||||
SelectedOptionItems.Clear();
|
||||
}
|
||||
|
||||
private void CreateOptions(IEnumerable<string> data)
|
||||
{
|
||||
if (IsInnerModel)
|
||||
{
|
||||
var d1 = data.Where(d => !SelectOptionItems.Any(o => o.Value == d));
|
||||
CreateOptionsByTreeNode(d1);
|
||||
return;
|
||||
}
|
||||
|
||||
data.ForEach(menuId =>
|
||||
{
|
||||
var d = DataItemExpression?.Invoke(DataSource, menuId);
|
||||
if (d != null)
|
||||
{
|
||||
var o = CreateOption(d, true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void CreateOptionsByTreeNode(IEnumerable<string> data)
|
||||
{
|
||||
data.ForEach(menuId =>
|
||||
{
|
||||
var d = _tree.FindFirstOrDefaultNode(n => n.Key == menuId);
|
||||
if (d != null)
|
||||
{
|
||||
var o = CreateOption(d, true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private SelectOptionItem<string, TItem> CreateOption(TreeNode<TItem> data, bool append = false)
|
||||
{
|
||||
var o = new SelectOptionItem<string, TItem>()
|
||||
{
|
||||
Label = data.Title,
|
||||
Value = data.Key,
|
||||
Item = data.DataItem,
|
||||
IsAddedTag = SelectMode != SelectMode.Default
|
||||
};
|
||||
if (append)
|
||||
SelectOptionItems.Add(o);
|
||||
return o;
|
||||
}
|
||||
|
||||
private SelectOptionItem<string, TItem> CreateOption(TItem data, bool append = false)
|
||||
{
|
||||
var o = new SelectOptionItem<string, TItem>()
|
||||
{
|
||||
Label = TitleExpression(data),
|
||||
Value = KeyExpression(data),
|
||||
Item = data,
|
||||
IsAddedTag = SelectMode != SelectMode.Default
|
||||
};
|
||||
if (append)
|
||||
SelectOptionItems.Add(o);
|
||||
return o;
|
||||
}
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
SelectOptions = "".ToRenderFragment();
|
||||
//_inputValue = Value;
|
||||
base.OnInitialized();
|
||||
}
|
||||
|
||||
|
||||
private void OnKeyDownAsync(KeyboardEventArgs args)
|
||||
{
|
||||
}
|
||||
|
||||
protected async void OnInputAsync(ChangeEventArgs e)
|
||||
{
|
||||
}
|
||||
|
||||
protected async Task OnKeyUpAsync(KeyboardEventArgs e)
|
||||
{
|
||||
}
|
||||
|
||||
protected async Task OnInputFocusAsync(FocusEventArgs _)
|
||||
{
|
||||
}
|
||||
|
||||
protected async Task OnInputBlurAsync(FocusEventArgs _)
|
||||
{
|
||||
}
|
||||
|
||||
private async Task OnOverlayVisibleChangeAsync(bool visible)
|
||||
{
|
||||
if (visible)
|
||||
{
|
||||
await SetDropdownStyleAsync();
|
||||
}
|
||||
}
|
||||
protected async Task OnRemoveSelectedAsync(SelectOptionItem<string, TItem> selectOption)
|
||||
{
|
||||
if (selectOption == null) throw new ArgumentNullException(nameof(selectOption));
|
||||
await SetValueAsync(selectOption);
|
||||
|
||||
foreach (var item in _tree.SelectedNodesDictionary.Select(x => x.Value).ToList())
|
||||
{
|
||||
if (item.Key == selectOption.Value)
|
||||
item.SetSelected(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private async Task OnTreeNodeClick(TreeEventArgs<TItem> args)
|
||||
{
|
||||
if (!args.Node.Selected)
|
||||
return;
|
||||
|
||||
var key = args.Node.Key;
|
||||
if (Value != null && Value.Equals(key))
|
||||
return;
|
||||
if (Values != null && Values.Contains(key))
|
||||
return;
|
||||
|
||||
var data = args.Node;
|
||||
SelectOptionItem<string, TItem> item;
|
||||
if (IsInnerModel)
|
||||
item = CreateOption(data, true);
|
||||
else
|
||||
item = CreateOption(data.DataItem, true);
|
||||
|
||||
//_selectedNodes.Add(data);
|
||||
|
||||
await SetValueAsync(item);
|
||||
|
||||
if (SelectMode == SelectMode.Default)
|
||||
await CloseAsync();
|
||||
}
|
||||
|
||||
|
||||
protected void OnTreeNodeUnSelect(TreeEventArgs<TItem> args)
|
||||
{
|
||||
if (args == null) throw new ArgumentNullException(nameof(args));
|
||||
var key = args.Node.Key;
|
||||
var nodes = SelectOptionItems.Where(o => o.Value == key).ToArray();
|
||||
foreach (var item in nodes)
|
||||
{
|
||||
_ = SetValueAsync(item);
|
||||
}
|
||||
}
|
||||
|
||||
protected async Task SetDropdownStyleAsync()
|
||||
{
|
||||
string maxWidth = "", minWidth = "", definedWidth = "";
|
||||
var domRect = await JsInvokeAsync<DomRect>(JSInteropConstants.GetBoundingClientRect, Ref);
|
||||
var width = domRect.Width.ToString("0.00", System.Globalization.CultureInfo.InvariantCulture);
|
||||
minWidth = $"min-width: {width}px;";
|
||||
if (DropdownMatchSelectWidth.IsT0 && DropdownMatchSelectWidth.AsT0)
|
||||
{
|
||||
definedWidth = $"width: {width}px;";
|
||||
}
|
||||
else if (DropdownMatchSelectWidth.IsT1)
|
||||
{
|
||||
definedWidth = $"width: {DropdownMatchSelectWidth.AsT1};";
|
||||
}
|
||||
if (!DropdownMaxWidth.Equals("auto", StringComparison.CurrentCultureIgnoreCase))
|
||||
maxWidth = $"max-width: {DropdownMaxWidth};";
|
||||
_dropdownStyle = minWidth + definedWidth + maxWidth;
|
||||
|
||||
if (Multiple)
|
||||
{
|
||||
if (_selectedValues == null)
|
||||
return;
|
||||
_tree._allNodes.ForEach(n => n.SetSelected(_selectedValues.Contains(n.Key)));
|
||||
}
|
||||
else
|
||||
{
|
||||
_tree?.FindFirstOrDefaultNode(node => node.Key == Value)?.SetSelected(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected override void SetClassMap()
|
||||
{
|
||||
var classPrefix = "ant-select";
|
||||
ClassMapper
|
||||
.Add(classPrefix)
|
||||
.Add("ant-tree-select")
|
||||
.If("ant-select-lg", () => Size == "large")
|
||||
.If("ant-select-rtl", () => _dir == "rtl")
|
||||
.If("ant-select-sm", () => Size == "rtl")
|
||||
.If("ant-select-disabled", () => Disabled)
|
||||
.If("ant-select-single", () => SelectMode == SelectMode.Default)
|
||||
.If($"ant-select-multiple", () => SelectMode != SelectMode.Default)
|
||||
.If("ant-select-show-arrow", () => !IsMultiple)
|
||||
.If("ant-select-show-search", () => !IsMultiple)
|
||||
.If("ant-select-allow-clear", () => AllowClear)
|
||||
.If("ant-select-open", () => Open)
|
||||
.If("ant-select-focused", () => Open || Focused)
|
||||
;
|
||||
}
|
||||
}
|
||||
}
|
@ -11,10 +11,14 @@
|
||||
foreach (var item in DataSource)
|
||||
{
|
||||
<TreeNode DataItem="@item" @key="item.GetHashCode()"></TreeNode>
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
else if (ChildContent!=null)
|
||||
{
|
||||
@ChildContent
|
||||
}
|
||||
else
|
||||
{
|
||||
@Nodes
|
||||
}
|
||||
</CascadingValue>
|
||||
|
@ -121,6 +121,9 @@ namespace AntDesign
|
||||
[Parameter]
|
||||
public RenderFragment Nodes { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public RenderFragment ChildContent { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// tree childnodes
|
||||
/// Add values when the node is initialized
|
||||
@ -186,6 +189,11 @@ namespace AntDesign
|
||||
{
|
||||
if (SelectedNodesDictionary.ContainsKey(treeNode.NodeId) == true)
|
||||
SelectedNodesDictionary.Remove(treeNode.NodeId);
|
||||
|
||||
if (OnUnSelect.HasDelegate)
|
||||
{
|
||||
OnUnSelect.InvokeAsync(new TreeEventArgs<TItem>(this, treeNode));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -310,9 +318,9 @@ namespace AntDesign
|
||||
public EventCallback<string[]> CheckedKeysChanged { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Dechecked all selected items
|
||||
/// Checks all nodes
|
||||
/// </summary>
|
||||
public void CheckedAll()
|
||||
public void CheckAll()
|
||||
{
|
||||
foreach (var item in ChildNodes)
|
||||
{
|
||||
@ -320,8 +328,10 @@ namespace AntDesign
|
||||
}
|
||||
}
|
||||
|
||||
// Decheck all of the checked nodes
|
||||
public void DecheckedAll()
|
||||
/// <summary>
|
||||
/// Unchecks all nodes
|
||||
/// </summary>
|
||||
public void UncheckAll()
|
||||
{
|
||||
foreach (var item in ChildNodes)
|
||||
{
|
||||
@ -499,6 +509,9 @@ namespace AntDesign
|
||||
[Parameter]
|
||||
public EventCallback<TreeEventArgs<TItem>> OnSelect { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public EventCallback<TreeEventArgs<TItem>> OnUnSelect { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Click the expansion tree node icon to call back
|
||||
/// </summary>
|
||||
|
@ -29,9 +29,13 @@
|
||||
foreach (var item in ChildDataItems)
|
||||
{
|
||||
<TreeNode DataItem="@item" @key="item.GetHashCode()"></TreeNode>
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
else if (ChildContent != null)
|
||||
{
|
||||
@ChildContent
|
||||
}
|
||||
else
|
||||
{
|
||||
@Nodes
|
||||
}
|
||||
|
@ -34,6 +34,9 @@ namespace AntDesign
|
||||
[Parameter]
|
||||
public RenderFragment Nodes { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public RenderFragment ChildContent { get; set; }
|
||||
|
||||
internal List<TreeNode<TItem>> ChildNodes { get; set; } = new List<TreeNode<TItem>>();
|
||||
|
||||
/// <summary>
|
||||
@ -501,7 +504,7 @@ namespace AntDesign
|
||||
hasUnchecked = true;
|
||||
break;
|
||||
}
|
||||
else if (item.Checked)
|
||||
else if (item.Checked)
|
||||
{
|
||||
hasChecked = true;
|
||||
}
|
||||
|
@ -93,6 +93,7 @@
|
||||
a&-ellipsis,
|
||||
span&-ellipsis {
|
||||
display: inline-block;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
a&,
|
||||
|
@ -3,7 +3,7 @@
|
||||
"AntDesign.Docs.Server": {
|
||||
"commandName": "Project",
|
||||
"launchBrowser": true,
|
||||
"applicationUrl": "https://localhost:5001",
|
||||
"applicationUrl": "http://localhost:5001",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
|
@ -0,0 +1,107 @@
|
||||
@using System.ComponentModel.DataAnnotations;
|
||||
@using System.Text.Json;
|
||||
@using System.ComponentModel
|
||||
|
||||
<Form Model="@model"
|
||||
LabelColSpan="8"
|
||||
WrapperColSpan="16">
|
||||
<FormItem Label="Fail" ValidateStatus=FormValidateStatus.Error Help="Should be combination of numbers & alphabets">
|
||||
<Input @bind-Value="@context.Username" Placeholder="unavailable choice" />
|
||||
</FormItem>
|
||||
<FormItem Label="Warning" ValidateStatus=FormValidateStatus.Warning>
|
||||
<Input @bind-Value="@context.Username" Placeholder="Warning">
|
||||
<Prefix>
|
||||
<Icon Type="smile" Theme="outline"/>
|
||||
</Prefix>
|
||||
</Input>
|
||||
</FormItem>
|
||||
<FormItem Label="Validating" HasFeedback ValidateStatus=FormValidateStatus.Validating Help="The information is being validated...">
|
||||
<Input @bind-Value="@context.Username" Placeholder="I'm the content being validated" />
|
||||
</FormItem>
|
||||
<FormItem Label="Success" HasFeedback ValidateStatus=FormValidateStatus.Success>
|
||||
<Input @bind-Value="@context.Username" Placeholder="I'm the content" />
|
||||
</FormItem>
|
||||
<FormItem Label="Warning" HasFeedback ValidateStatus=FormValidateStatus.Warning>
|
||||
<Input @bind-Value="@context.Username" Placeholder="Warning" />
|
||||
</FormItem>
|
||||
<FormItem Label="Fail" HasFeedback ValidateStatus=FormValidateStatus.Error Help="Should be combination of numbers & alphabets">
|
||||
<Input @bind-Value="@context.Username" Placeholder="unavailable choice" />
|
||||
</FormItem>
|
||||
<FormItem Label="Success" HasFeedback ValidateStatus=FormValidateStatus.Success>
|
||||
<DatePicker @bind-Value="@context.DatePicker" Picker="@DatePickerType.Date" Style="width: 100%;" />
|
||||
</FormItem>
|
||||
<FormItem Label="Warning" HasFeedback ValidateStatus=FormValidateStatus.Warning>
|
||||
<TimePicker @bind-Value="@context.TimePicker" Style="width: 100%;" />
|
||||
</FormItem>
|
||||
<FormItem Label="Error" HasFeedback ValidateStatus=FormValidateStatus.Error>
|
||||
<Select DataSource="@_options"
|
||||
@bind-Value="@context.SelectedOption"
|
||||
AllowClear>
|
||||
</Select>
|
||||
</FormItem>
|
||||
<FormItem Label="Validating" HasFeedback ValidateStatus=FormValidateStatus.Validating Help="The information is being validated...">
|
||||
<Select DataSource="@_options2"
|
||||
@bind-Value="@context.SelectedOption2"
|
||||
AllowClear
|
||||
Placeholder="Please select">
|
||||
</Select>
|
||||
</FormItem>
|
||||
<FormItem Label="inline" Style="margin-bottom: 0;">
|
||||
<ChildContent>
|
||||
<div style="display:grid;grid-template-columns:45% 1fr 45%;">
|
||||
<FormItem ValidateStatus=FormValidateStatus.Error Help="Please select the correct date">
|
||||
<DatePicker @bind-Value="@context.DatePicker2" Style="width:100%;"/>
|
||||
</FormItem>
|
||||
<span style="text-align:center;">-</span>
|
||||
<FormItem>
|
||||
<DatePicker @bind-Value="@context.DatePicker3" Style="width:100%;" />
|
||||
</FormItem>
|
||||
</div>
|
||||
</ChildContent>
|
||||
</FormItem>
|
||||
<FormItem Label="Success" HasFeedback ValidateStatus=FormValidateStatus.Success>
|
||||
<AntDesign.InputNumber @bind-Value="@context.InputNumber" Style="width:100%;"></AntDesign.InputNumber>
|
||||
</FormItem>
|
||||
<FormItem Label="Success" HasFeedback ValidateStatus=FormValidateStatus.Success>
|
||||
<AntDesign.Input @bind-Value="@context.Input" AllowClear Placeholder="with allowClear"></AntDesign.Input>
|
||||
</FormItem>
|
||||
<FormItem Label="Warning" HasFeedback ValidateStatus=FormValidateStatus.Warning>
|
||||
<AntDesign.InputPassword @bind-Value="@context.Password" Placeholder="with input password"></AntDesign.InputPassword>
|
||||
</FormItem>
|
||||
<FormItem Label="Error" HasFeedback ValidateStatus=FormValidateStatus.Error>
|
||||
<AntDesign.InputPassword @bind-Value="@context.Password" AllowClear Placeholder="with input password and allowClear"></AntDesign.InputPassword>
|
||||
</FormItem>
|
||||
</Form>
|
||||
@code
|
||||
{
|
||||
public class Model
|
||||
{
|
||||
public string Username { get; set; }
|
||||
public DateTime? DatePicker { get; set; }
|
||||
public DateTime? TimePicker { get; set; }
|
||||
public string SelectedOption { get; set; }
|
||||
public string SelectedOption2 { get; set; }
|
||||
public DateTime? DatePicker2 { get; set; }
|
||||
public DateTime? DatePicker3 { get; set; }
|
||||
public int? InputNumber { get; set; }
|
||||
public string Input { get; set; }
|
||||
public string Password { get; set; }
|
||||
}
|
||||
|
||||
private Model model = new Model();
|
||||
|
||||
private List<string> _options;
|
||||
private List<string> _options2;
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
_options = new List<string>
|
||||
{
|
||||
"Option 1", "Option 2", "Option 3"
|
||||
};
|
||||
_options2 = new List<string>
|
||||
{
|
||||
"Option 1", "Option 2", "Option 3"
|
||||
};
|
||||
}
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
---
|
||||
order: 102
|
||||
title:
|
||||
zh-CN: 自定义校验
|
||||
en-US: Customized Validation
|
||||
---
|
||||
|
||||
## zh-CN
|
||||
|
||||
我们提供了 `validateStatus` `help` `hasFeedback` 等属性,你可以不通过 Form 自己定义校验的时机和内容。
|
||||
|
||||
1. `validateStatus`: 校验状态,可选 'success', 'warning', 'error', 'validating'。
|
||||
2. `hasFeedback`:用于给输入框添加反馈图标。
|
||||
3. `help`:设置校验文案。
|
||||
|
||||
## en-US
|
||||
|
||||
We provide properties like `validateStatus` `help` `hasFeedback` to customize your own validate status and message, without using Form.
|
||||
|
||||
1. `validateStatus`: validate status of form components which could be 'success', 'warning', 'error', 'validating'.
|
||||
2. `hasFeedback`: display feed icon of input control
|
||||
3. `help`: display validate message.
|
@ -1,6 +1,6 @@
|
||||
|
||||
<div style="display: flex; justify-content: space-between;">
|
||||
<RadioGroup @bind-Value="currentTheme" ButtonStyle="solid" Size="large" TValue="string" OnChange="OnThemeChanged">
|
||||
<RadioGroup @bind-Value="currentTheme" ButtonStyle="@RadioButtonStyle.Solid" Size="large" TValue="string" OnChange="OnThemeChanged">
|
||||
<Radio RadioButton Value="@("outline")">
|
||||
<Icon Component="OutlineSvg" />@LanguageService.Resources["app.docs.components.icon.outlined"]
|
||||
</Radio>
|
||||
|
@ -0,0 +1,18 @@
|
||||
<div>
|
||||
<Image PreviewVisible="false"
|
||||
Width="200"
|
||||
Src="https://gw.alipayobjects.com/zos/antfincdn/LlvErxo8H9/photo-1503185912284-5271ff81b9a8.webp"
|
||||
OnClick="@(() => { visible = true; })" />
|
||||
<div style="display:none;">
|
||||
<ImagePreviewGroup @bind-PreviewVisible="visible" >
|
||||
<Image Src="https://gw.alipayobjects.com/zos/antfincdn/LlvErxo8H9/photo-1503185912284-5271ff81b9a8.webp" />
|
||||
<Image Src="https://gw.alipayobjects.com/zos/antfincdn/cV16ZqzMjW/photo-1473091540282-9b846e7965e3.webp" />
|
||||
<Image Src="https://gw.alipayobjects.com/zos/antfincdn/x43I27A55%26/photo-1438109491414-7198515b166b.webp" />
|
||||
</ImagePreviewGroup>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@code {
|
||||
bool visible;
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
---
|
||||
order: 6
|
||||
title:
|
||||
zh-CN: 相册模式
|
||||
en-US: Preview from one image
|
||||
---
|
||||
|
||||
## zh-CN
|
||||
|
||||
从一张图片点开相册。
|
||||
|
||||
## en-US
|
||||
|
||||
Preview a collection from one image.
|
@ -15,6 +15,8 @@ Previewable image.
|
||||
|
||||
## API
|
||||
|
||||
### Image
|
||||
|
||||
| Property | Description | Type | Default | Version |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| Alt | Image description | string | - | 0.6.0 |
|
||||
@ -22,8 +24,15 @@ Previewable image.
|
||||
| Height | Image height | string | - | 0.6.0 |
|
||||
| Locale | Locale Object | ImageLocale | - |- |
|
||||
| Placeholder | Load placeholder | RenderFragment | - | 0.6.0 |
|
||||
| Preview | preview config, disabled when `false` | boolean | true | 0.6.0 |
|
||||
| Preview | Whether to enable the preview function | boolean | true | 0.6.0 |
|
||||
| PreviewSrc | path of the preview image before loading is complete | string | the same as `Src` | 0.6.0 |
|
||||
| PreviewVisible | Whether to open the preview image when clicking the preview button | true | 0.10.0 |
|
||||
| Src | Image path | string | - | 0.6.0 |
|
||||
| Width | Image width | string | - | 0.6.0 |
|
||||
| OnClick | Triggered when the image is clicked | EventCallback<MouseEventArgs> | 0.10.0 |
|
||||
|
||||
### ImagePreviewGroup
|
||||
|
||||
| Property | Description | Type | Default | Version |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| PreviewVisible | Whether to open the preview image. Two-way binding. | bool | true | 0.10.0 |
|
@ -16,6 +16,8 @@ cover: https://gw.alipayobjects.com/zos/antfincdn/D1dXz9PZqa/image.svg
|
||||
|
||||
## API
|
||||
|
||||
### Image
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| Alt | 图像描述 | string | - | 0.6.0 |
|
||||
@ -23,7 +25,16 @@ cover: https://gw.alipayobjects.com/zos/antfincdn/D1dXz9PZqa/image.svg
|
||||
| Height | 图像高度 | string | - | 4.6.0 |
|
||||
| Locale | 语言对象 | ImageLocale | - |- |
|
||||
| Placeholder | 加载占位 | RenderFragment | - | 0.6.0 |
|
||||
| Preview | 预览参数,为 `false` 时禁用 | boolean | true | 0.6.0 |
|
||||
| Preview | 设置是否启用预览功能 | bool | true | 0.6.0 |
|
||||
| PreviewSrc | 加载完成前预览图的地址 | string | 与 `Src` 一样 | 0.6.0 |
|
||||
| PreviewVisible | 设置是否在点击预览按钮时打开预览框。 | true | 0.10.0 |
|
||||
| Src | 图片地址 | string | - | 0.6.0 |
|
||||
| Width | 图像宽度 | string | - | 0.6.0 |
|
||||
| OnClick | 在点击图片时触发 | EventCallback<MouseEventArgs> | 0.10.0 |
|
||||
|
||||
|
||||
### ImagePreviewGroup
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| PreviewVisible | 是否打开预览图片。支持双向绑定。 | bool | true | 0.10.0 |
|
@ -1,5 +1,5 @@
|
||||
<div>
|
||||
<RadioGroup @bind-Value="radioValue4" ButtonStyle="solid">
|
||||
<RadioGroup @bind-Value="radioValue4" ButtonStyle="@RadioButtonStyle.Solid">
|
||||
<Radio RadioButton Value="@("A")">Hangzhou</Radio>
|
||||
<Radio RadioButton Value="@("B")">Shanghai</Radio>
|
||||
<Radio RadioButton Value="@("C")">Beijing</Radio>
|
||||
|
@ -0,0 +1,19 @@
|
||||
@using System.ComponentModel.DataAnnotations
|
||||
|
||||
<EnumRadioGroup TEnum="Fruits" @bind-Value="_radioValue"></EnumRadioGroup>
|
||||
<br />
|
||||
Value: @_radioValue
|
||||
|
||||
@code {
|
||||
Fruits _radioValue = Fruits.Apple;
|
||||
|
||||
enum Fruits
|
||||
{
|
||||
[Display(Name = "🍎 Apple")]
|
||||
Apple,
|
||||
|
||||
Pear,
|
||||
|
||||
Orange
|
||||
}
|
||||
}
|
@ -1,12 +1,16 @@
|
||||
<RadioGroup @bind-Value="_radioValue">
|
||||
@foreach (var item in options)
|
||||
{
|
||||
<Radio Value="@item">@item</Radio>
|
||||
}
|
||||
</RadioGroup>
|
||||
<RadioGroup Options="@options" @bind-Value="_radioValue"></RadioGroup>
|
||||
<br />
|
||||
<RadioGroup Options="@options2" @bind-Value="_radioValue"></RadioGroup>
|
||||
|
||||
|
||||
@code {
|
||||
string _radioValue = "Apple";
|
||||
string _radioValue = "Apple";
|
||||
string[] options = new string[] { "Apple", "Pear", "Orange" };
|
||||
|
||||
RadioOption<string>[] options2 = new RadioOption<string>[]
|
||||
{
|
||||
new(){ Value = "Apple", Label="🍎 Apple", },
|
||||
new(){ Value = "Pear", Label="🍐 Pear", },
|
||||
new(){ Value = "Orange", Label="🍊 Orange", },
|
||||
};
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
---
|
||||
order: 8.5
|
||||
title:
|
||||
zh-CN: RadioGroup 组合 - 枚举方式
|
||||
en-US: Radio group - enum type
|
||||
---
|
||||
|
||||
## zh-CN
|
||||
|
||||
通过指定枚举类型,来渲染单选框。
|
||||
|
||||
|
||||
## en-US
|
||||
|
||||
Render radios by specific enum type.
|
@ -16,3 +16,16 @@ A table displays rows of data.
|
||||
## How To Use
|
||||
|
||||
Specify `dataSource` of Table as an array of data.
|
||||
|
||||
|
||||
## API
|
||||
|
||||
TODO
|
||||
|
||||
### Responsive
|
||||
|
||||
The table supports responsive by default, and when the screen width is less than 960px, the table would switch to small-screen mode.
|
||||
|
||||
In small-screen mode, only certain features are currently supported, and mis-styling will occur in tables with some features such as group, expanded columns, tree data, summary cell, etc.
|
||||
|
||||
If you want to disable responsive, you can set `Responsive="false"`.
|
@ -17,3 +17,15 @@ cover: https://gw.alipayobjects.com/zos/alicdn/f-SbcX2Lx/Table.svg
|
||||
## 如何使用
|
||||
|
||||
指定表格的数据源 `dataSource` 为一个数组。
|
||||
|
||||
|
||||
## API
|
||||
|
||||
TODO
|
||||
|
||||
### 响应式
|
||||
|
||||
表格默认支持响应式,当屏幕宽度小于 960px 时,表格的数据列变为小屏模式。
|
||||
|
||||
在小屏模式下,目前只支持一定的表格功能,在有 分组合并、展开列、树形数据、总结栏 等属性的表格中会出现样式错乱。
|
||||
如果想禁用响应式,可以设置 `Responsive="false"`。
|
@ -1,5 +1,5 @@
|
||||
<div>
|
||||
<Timeline Mode="alternate" >
|
||||
<Timeline Mode="@TimelineMode.Alternate" >
|
||||
<TimelineItem>Create a services site 2015-09-01</TimelineItem>
|
||||
<TimelineItem Color="green">Solve initial network problems 2015-09-01</TimelineItem>
|
||||
<TimelineItem Dot="dotTemplate">
|
||||
|
@ -1,19 +1,17 @@
|
||||
<div>
|
||||
<RadioGroup @bind-Value="@mode" Style="margin-bottom:20px">
|
||||
<Radio Value="@("left")">Left</Radio>
|
||||
<Radio Value="@("right")">Right</Radio>
|
||||
<Radio Value="@("alternate")">Alternate</Radio>
|
||||
<Radio Value="@TimelineMode.Left">Left</Radio>
|
||||
<Radio Value="@TimelineMode.Right">Right</Radio>
|
||||
<Radio Value="@TimelineMode.Alternate">Alternate</Radio>
|
||||
</RadioGroup>
|
||||
<Timeline Mode="@mode">
|
||||
<TimelineItem>Create a services 2015-09-01</TimelineItem>
|
||||
<TimelineItem>Solve initial network problems 2015-09-01 09:12:11</TimelineItem>
|
||||
<TimelineItem Label="2015-09-01">Create a services</TimelineItem>
|
||||
<TimelineItem Label="2015-09-01 09:12:11">Solve initial network problems</TimelineItem>
|
||||
<TimelineItem>Technical testing</TimelineItem>
|
||||
<TimelineItem>Network problems being solved 2015-09-01 09:12:11</TimelineItem>
|
||||
<TimelineItem Label="2015-09-01 09:12:11">Network problems being solved</TimelineItem>
|
||||
</Timeline>
|
||||
</div>
|
||||
|
||||
@code{
|
||||
private string mode = "left";
|
||||
|
||||
|
||||
private TimelineMode mode = TimelineMode.Left;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
<div>
|
||||
<Timeline Mode="right">
|
||||
<Timeline Mode="@TimelineMode.Right">
|
||||
<TimelineItem>Create a services site 2015-09-01</TimelineItem>
|
||||
<TimelineItem>Solve initial network problems 2015-09-01</TimelineItem>
|
||||
<TimelineItem Dot="dotTemplate" Color="red">
|
||||
|
@ -1,34 +1,26 @@
|
||||
<Tree TItem="string" Checkable
|
||||
DefaultExpandedKeys="@(new[] { "0-0-0", "0-0-1"})"
|
||||
DefaultSelectedKeys="@(new[] {"0-0-0", "0-0-1" })"
|
||||
DefaultCheckedKeys="@(new[] {"0-0-0", "0-0-1" })"
|
||||
SelectedNodeChanged="SelectedNodeChanged"
|
||||
OnSelect="OnSelect"
|
||||
OnCheck="OnCheck">
|
||||
<Nodes>
|
||||
<TreeNode Title="parent 1" Key="0-0" TItem="string">
|
||||
<Nodes>
|
||||
<TreeNode Title="parent 1-0" Key="0-0-0" Disabled TItem="string">
|
||||
<Nodes>
|
||||
<TreeNode Title="leaf" Key="0-0-0-0" DisableCheckbox TItem="string"></TreeNode>
|
||||
<TreeNode Title="leaf" Key="0-0-0-1" TItem="string"></TreeNode>
|
||||
</Nodes>
|
||||
</TreeNode>
|
||||
<TreeNode Title="parent 1-1" Key="0-0-1" TItem="string">
|
||||
<Nodes>
|
||||
<TreeNode Key="0-0-1-0" TItem="string">
|
||||
<TitleTemplate>
|
||||
<span style="color: #1890ff; ">sss</span>
|
||||
</TitleTemplate>
|
||||
</TreeNode>
|
||||
</Nodes>
|
||||
</TreeNode>
|
||||
</Nodes>
|
||||
</TreeNode>
|
||||
</Nodes>
|
||||
DefaultExpandedKeys="@(new[] { "0-0-0", "0-0-1"})"
|
||||
DefaultSelectedKeys="@(new[] {"0-0-0", "0-0-1" })"
|
||||
DefaultCheckedKeys="@(new[] {"0-0-0", "0-0-1" })"
|
||||
SelectedNodeChanged="SelectedNodeChanged"
|
||||
OnSelect="OnSelect"
|
||||
OnCheck="OnCheck">
|
||||
<TreeNode Title="parent 1" Key="0-0" TItem="string">
|
||||
<TreeNode Title="parent 1-0" Key="0-0-0" Disabled TItem="string">
|
||||
<TreeNode Title="leaf" Key="0-0-0-0" DisableCheckbox TItem="string"></TreeNode>
|
||||
<TreeNode Title="leaf" Key="0-0-0-1" TItem="string"></TreeNode>
|
||||
</TreeNode>
|
||||
<TreeNode Title="parent 1-1" Key="0-0-1" TItem="string">
|
||||
<TreeNode Key="0-0-1-0" TItem="string">
|
||||
<TitleTemplate>
|
||||
<span style="color: #1890ff; ">sss</span>
|
||||
</TitleTemplate>
|
||||
</TreeNode>
|
||||
</TreeNode>
|
||||
</TreeNode>
|
||||
</Tree>
|
||||
|
||||
@code{
|
||||
@code {
|
||||
|
||||
void OnSelect(TreeEventArgs<string> args)
|
||||
{
|
||||
|
@ -1,42 +1,32 @@
|
||||
<Tree @ref="_tree"
|
||||
Checkable
|
||||
TItem="string"
|
||||
@bind-ExpandedKeys="expandedKeys"
|
||||
@bind-CheckedKeys="checkedKeys"
|
||||
@bind-SelectedKeys="selectedKeys"
|
||||
OnExpand="OnExpand"
|
||||
OnSelect="OnSelect"
|
||||
OnCheck="OnCheck"
|
||||
AutoExpandParent="autoExpandParent">
|
||||
<Nodes>
|
||||
<TreeNode Title="0-0" Key="0-0" TItem="string">
|
||||
<Nodes>
|
||||
<TreeNode Title="0-0-0" Key="0-0-0" TItem="string">
|
||||
<Nodes>
|
||||
<TreeNode Title="0-0-0-0" Key="0-0-0-0" TItem="string"></TreeNode>
|
||||
<TreeNode Title="0-0-0-1" Key="0-0-0-1" TItem="string"></TreeNode>
|
||||
<TreeNode Title="0-0-0-2" Key="0-0-0-2" TItem="string"></TreeNode>
|
||||
</Nodes>
|
||||
</TreeNode>
|
||||
<TreeNode Title="0-0-1" Key="0-0-1" TItem="string">
|
||||
<Nodes>
|
||||
<TreeNode Title="0-0-1-0" Key="0-0-1-0" TItem="string"></TreeNode>
|
||||
<TreeNode Title="0-0-1-1" Key="0-0-1-1" TItem="string"></TreeNode>
|
||||
<TreeNode Title="0-0-1-2" Key="0-0-1-2" TItem="string"></TreeNode>
|
||||
</Nodes>
|
||||
</TreeNode>
|
||||
<TreeNode Title="0-0-2" Key="0-0-2" TItem="string"></TreeNode>
|
||||
</Nodes>
|
||||
</TreeNode>
|
||||
<TreeNode Title="0-1" Key="0-1" TItem="string">
|
||||
<Nodes>
|
||||
<TreeNode Title="0-1-0-0" Key="0-1-0-0" TItem="string"></TreeNode>
|
||||
<TreeNode Title="0-1-0-1" Key="0-1-0-1" DisableCheckbox TItem="string"></TreeNode>
|
||||
<TreeNode Title="0-1-0-2" Key="0-1-0-2" Disabled TItem="string"></TreeNode>
|
||||
</Nodes>
|
||||
</TreeNode>
|
||||
<TreeNode Title="0-2" Key="0-2" TItem="string"></TreeNode>
|
||||
</Nodes>
|
||||
Checkable
|
||||
TItem="string"
|
||||
@bind-ExpandedKeys="expandedKeys"
|
||||
@bind-CheckedKeys="checkedKeys"
|
||||
@bind-SelectedKeys="selectedKeys"
|
||||
OnExpand="OnExpand"
|
||||
OnSelect="OnSelect"
|
||||
OnCheck="OnCheck"
|
||||
AutoExpandParent="autoExpandParent">
|
||||
<TreeNode Title="0-0" Key="0-0" TItem="string">
|
||||
<TreeNode Title="0-0-0" Key="0-0-0" TItem="string">
|
||||
<TreeNode Title="0-0-0-0" Key="0-0-0-0" TItem="string"></TreeNode>
|
||||
<TreeNode Title="0-0-0-1" Key="0-0-0-1" TItem="string"></TreeNode>
|
||||
<TreeNode Title="0-0-0-2" Key="0-0-0-2" TItem="string"></TreeNode>
|
||||
</TreeNode>
|
||||
<TreeNode Title="0-0-1" Key="0-0-1" TItem="string">
|
||||
<TreeNode Title="0-0-1-0" Key="0-0-1-0" TItem="string"></TreeNode>
|
||||
<TreeNode Title="0-0-1-1" Key="0-0-1-1" TItem="string"></TreeNode>
|
||||
<TreeNode Title="0-0-1-2" Key="0-0-1-2" TItem="string"></TreeNode>
|
||||
</TreeNode>
|
||||
<TreeNode Title="0-0-2" Key="0-0-2" TItem="string"></TreeNode>
|
||||
</TreeNode>
|
||||
<TreeNode Title="0-1" Key="0-1" TItem="string">
|
||||
<TreeNode Title="0-1-0-0" Key="0-1-0-0" TItem="string"></TreeNode>
|
||||
<TreeNode Title="0-1-0-1" Key="0-1-0-1" DisableCheckbox TItem="string"></TreeNode>
|
||||
<TreeNode Title="0-1-0-2" Key="0-1-0-2" Disabled TItem="string"></TreeNode>
|
||||
</TreeNode>
|
||||
<TreeNode Title="0-2" Key="0-2" TItem="string"></TreeNode>
|
||||
</Tree>
|
||||
|
||||
<br />
|
||||
@ -44,7 +34,8 @@
|
||||
|
||||
<Button OnClick="PrintCheckedNodesKey">Print Checked Nodes Key</Button>
|
||||
|
||||
<Button OnClick="DecheckedAll">Dechecked All</Button>
|
||||
<Button OnClick="CheckAll">Check all nodes</Button>
|
||||
<Button OnClick="UncheckAll">Uncheck all nodes</Button>
|
||||
<br />
|
||||
<br />
|
||||
|
||||
@ -59,78 +50,83 @@
|
||||
|
||||
@if (string.IsNullOrWhiteSpace(printType) == false)
|
||||
{
|
||||
<div>@printType</div>
|
||||
<ul>
|
||||
@foreach (var item in printTexts)
|
||||
{
|
||||
<li>@item</li>
|
||||
}
|
||||
</ul>
|
||||
<div>@printType</div>
|
||||
<ul>
|
||||
@foreach (var item in printTexts)
|
||||
{
|
||||
<li>@item</li>
|
||||
}
|
||||
</ul>
|
||||
}
|
||||
@code {
|
||||
|
||||
string printType;
|
||||
string printType;
|
||||
|
||||
string[] printTexts;
|
||||
string[] printTexts;
|
||||
|
||||
Tree<string> _tree;
|
||||
Tree<string> _tree;
|
||||
|
||||
string[] expandedKeys;
|
||||
string[] checkedKeys;
|
||||
string[] selectedKeys;
|
||||
string[] expandedKeys;
|
||||
string[] checkedKeys;
|
||||
string[] selectedKeys;
|
||||
|
||||
bool autoExpandParent;
|
||||
bool autoExpandParent;
|
||||
|
||||
//private void PrintCheckedNodesTitle()
|
||||
//{
|
||||
// printType = "CheckedNodesTitle";
|
||||
// printTexts = tree.CheckedTitles;
|
||||
//}
|
||||
//private void PrintCheckedNodesTitle()
|
||||
//{
|
||||
// printType = "CheckedNodesTitle";
|
||||
// printTexts = tree.CheckedTitles;
|
||||
//}
|
||||
|
||||
private void PrintCheckedNodesKey()
|
||||
{
|
||||
printType = "CheckedNodesKey";
|
||||
printTexts = _tree.CheckedKeys;
|
||||
}
|
||||
private void PrintCheckedNodesKey()
|
||||
{
|
||||
printType = "CheckedNodesKey";
|
||||
printTexts = _tree.CheckedKeys;
|
||||
}
|
||||
|
||||
private void DecheckedAll()
|
||||
{
|
||||
_tree.DecheckedAll();
|
||||
}
|
||||
private void CheckAll()
|
||||
{
|
||||
_tree.CheckAll();
|
||||
}
|
||||
|
||||
//private void PrintSelectedNodes()
|
||||
//{
|
||||
// printType = "SelectedNodes";
|
||||
// printTexts = tree.SelectedTitles;
|
||||
//}
|
||||
private void UncheckAll()
|
||||
{
|
||||
_tree.UncheckAll();
|
||||
}
|
||||
|
||||
private void DeselectAll()
|
||||
{
|
||||
_tree.DeselectAll();
|
||||
}
|
||||
//private void PrintSelectedNodes()
|
||||
//{
|
||||
// printType = "SelectedNodes";
|
||||
// printTexts = tree.SelectedTitles;
|
||||
//}
|
||||
|
||||
private void ExpandAll()
|
||||
{
|
||||
_tree.ExpandAll();
|
||||
}
|
||||
private void DeselectAll()
|
||||
{
|
||||
_tree.DeselectAll();
|
||||
}
|
||||
|
||||
private void CollapseAll()
|
||||
{
|
||||
_tree.CollapseAll();
|
||||
}
|
||||
private void ExpandAll()
|
||||
{
|
||||
_tree.ExpandAll();
|
||||
}
|
||||
|
||||
private void OnCheck(TreeEventArgs<string> e)
|
||||
{
|
||||
Console.WriteLine("OnCheck:" + e.Node.Key);
|
||||
}
|
||||
private void CollapseAll()
|
||||
{
|
||||
_tree.CollapseAll();
|
||||
}
|
||||
|
||||
private void OnSelect(TreeEventArgs<string> e)
|
||||
{
|
||||
Console.WriteLine("OnSelect:" + e.Node.Key);
|
||||
}
|
||||
private void OnCheck(TreeEventArgs<string> e)
|
||||
{
|
||||
Console.WriteLine("OnCheck:" + e.Node.Key);
|
||||
}
|
||||
|
||||
private void OnExpand((string[] ExpandedKeys, TreeNode<string> Node, bool Expanded) e)
|
||||
{
|
||||
Console.WriteLine("OnExpand:" + JsonSerializer.Serialize(e.ExpandedKeys));
|
||||
}
|
||||
private void OnSelect(TreeEventArgs<string> e)
|
||||
{
|
||||
Console.WriteLine("OnSelect:" + e.Node.Key);
|
||||
}
|
||||
|
||||
private void OnExpand((string[] ExpandedKeys, TreeNode<string> Node, bool Expanded) e)
|
||||
{
|
||||
Console.WriteLine("OnExpand:" + JsonSerializer.Serialize(e.ExpandedKeys));
|
||||
}
|
||||
}
|
@ -1,32 +1,29 @@
|
||||
<Tree TItem="string"
|
||||
ShowIcon
|
||||
DefaultExpandAll
|
||||
DefaultSelectedKeys="@(new[]{"0-0-0"})"
|
||||
>
|
||||
<SwitcherIconTemplate>
|
||||
@switcherIcon
|
||||
</SwitcherIconTemplate>
|
||||
<Nodes>
|
||||
<TreeNode Title="parent 1" Key="0-0" Icon="smile" TItem="string">
|
||||
<Nodes>
|
||||
<TreeNode Title="leaf" Key="0-0-0" Icon="meh" TItem="string" />
|
||||
</Nodes>
|
||||
</TreeNode>
|
||||
<TreeNode Title="leaf" Key="0-0-1" TItem="string">
|
||||
<IconTemplate Context="node">
|
||||
@if (node.Selected)
|
||||
{
|
||||
<Icon Type="frown" Theme="fill" />
|
||||
}
|
||||
else
|
||||
{
|
||||
<Icon Type="frown" Theme="outline" />
|
||||
}
|
||||
</IconTemplate>
|
||||
</TreeNode>
|
||||
</Nodes>
|
||||
<Tree TItem="string"
|
||||
ShowIcon
|
||||
DefaultExpandAll
|
||||
DefaultSelectedKeys="@(new[]{"0-0-0"})">
|
||||
<SwitcherIconTemplate>
|
||||
@switcherIcon
|
||||
</SwitcherIconTemplate>
|
||||
<Nodes>
|
||||
<TreeNode Title="parent 1" Key="0-0" Icon="smile" TItem="string">
|
||||
<TreeNode Title="leaf" Key="0-0-0" Icon="meh" TItem="string" />
|
||||
</TreeNode>
|
||||
<TreeNode Title="leaf" Key="0-0-1" TItem="string">
|
||||
<IconTemplate Context="node">
|
||||
@if (node.Selected)
|
||||
{
|
||||
<Icon Type="frown" Theme="fill" />
|
||||
}
|
||||
else
|
||||
{
|
||||
<Icon Type="frown" Theme="outline" />
|
||||
}
|
||||
</IconTemplate>
|
||||
</TreeNode>
|
||||
</Nodes>
|
||||
</Tree>
|
||||
|
||||
@code {
|
||||
RenderFragment switcherIcon =@<Icon Type="down" />;
|
||||
RenderFragment switcherIcon =@<Icon Type="down" />;
|
||||
}
|
||||
|
@ -1,32 +1,26 @@
|
||||
<DirectoryTree TItem="string"
|
||||
Multiple
|
||||
DefaultExpandAll
|
||||
OnSelect="OnSelect"
|
||||
OnExpand="OnExpand">
|
||||
<Nodes>
|
||||
<TreeNode Title="parent 0" Key="0-0" TItem="string">
|
||||
<Nodes>
|
||||
<TreeNode Title="leaf 0-0" Key="0-0-0" TItem="string" />
|
||||
<TreeNode Title="leaf 0-1" Key="0-0-1" TItem="string" />
|
||||
</Nodes>
|
||||
</TreeNode>
|
||||
<TreeNode Title="parent 1" Key="0-1" TItem="string">
|
||||
<Nodes>
|
||||
<TreeNode Title="leaf 1-0" Key="0-1-0" TItem="string" />
|
||||
<TreeNode Title="leaf 1-1" Key="0-1-1" TItem="string" />
|
||||
</Nodes>
|
||||
</TreeNode>
|
||||
</Nodes>
|
||||
Multiple
|
||||
DefaultExpandAll
|
||||
OnSelect="OnSelect"
|
||||
OnExpand="OnExpand">
|
||||
<TreeNode Title="parent 0" Key="0-0" TItem="string">
|
||||
<TreeNode Title="leaf 0-0" Key="0-0-0" TItem="string" />
|
||||
<TreeNode Title="leaf 0-1" Key="0-0-1" TItem="string" />
|
||||
</TreeNode>
|
||||
<TreeNode Title="parent 1" Key="0-1" TItem="string">
|
||||
<TreeNode Title="leaf 1-0" Key="0-1-0" TItem="string" />
|
||||
<TreeNode Title="leaf 1-1" Key="0-1-1" TItem="string" />
|
||||
</TreeNode>
|
||||
</DirectoryTree>
|
||||
|
||||
@code {
|
||||
void OnSelect()
|
||||
{
|
||||
void OnSelect()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void OnExpand()
|
||||
{
|
||||
void OnExpand()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,74 +1,59 @@
|
||||
<div>
|
||||
<div style="margin-bottom: 16px">
|
||||
showLine: <Switch @bind-Checked="_showLine" />
|
||||
<br />
|
||||
<br />
|
||||
showIcon: <Switch @bind-Checked="_showIcon" />
|
||||
<br />
|
||||
<br />
|
||||
showLeafIcon: <Switch @bind-Checked="_showLeafIcon" />
|
||||
</div>
|
||||
<div style="margin-bottom: 16px">
|
||||
showLine: <Switch @bind-Checked="_showLine" />
|
||||
<br />
|
||||
<br />
|
||||
showIcon: <Switch @bind-Checked="_showIcon" />
|
||||
<br />
|
||||
<br />
|
||||
showLeafIcon: <Switch @bind-Checked="_showLeafIcon" />
|
||||
</div>
|
||||
|
||||
<Tree
|
||||
ShowLine="@_showLine"
|
||||
ShowIcon="@_showIcon"
|
||||
ShowLeafIcon="@_showLeafIcon"
|
||||
DefaultExpandedKeys="@(new[]{"0-0-0"})"
|
||||
OnSelect="OnSelect"
|
||||
TItem="string">
|
||||
<Nodes>
|
||||
<TreeNode Title="parent 1" Key="0-0" Icon="carry-out" TItem="string">
|
||||
<Nodes>
|
||||
<TreeNode Title="parent 1-0" Key="0-0-0" Icon="carry-out" TItem="string">
|
||||
<Nodes>
|
||||
<TreeNode Title="leaf" Key="0-0-0-0" Icon="carry-out" TItem="string" />
|
||||
<TreeNode Key="0-0-0-1" Icon="carry-out" TItem="string">
|
||||
<TitleTemplate>
|
||||
<div>
|
||||
<div>multiple line title</div>
|
||||
<div>multiple line title</div>
|
||||
</div>
|
||||
</TitleTemplate>
|
||||
</TreeNode>
|
||||
<TreeNode Title="leaf" Key="0-0-0-2" Icon="carry-out" TItem="string" />
|
||||
</Nodes>
|
||||
</TreeNode>
|
||||
<TreeNode Title="parent 1-1" Key="0-0-1" Icon="carry-out" TItem="string">
|
||||
<Nodes>
|
||||
<TreeNode Title="left" Key="0-0-1-0" Icon="carry-out" TItem="string" />
|
||||
</Nodes>
|
||||
</TreeNode>
|
||||
<TreeNode Title="parent 1-2" Key="0-0-2" Icon="carry-out" TItem="string">
|
||||
<Nodes>
|
||||
<TreeNode Title="leaf" Key="0-0-2-0" Icon="carry-out" TItem="string" />
|
||||
<TreeNode Title="leaf" Key="0-0-2-1" Icon="carry-out" TItem="string" SwitcherIcon="form" />
|
||||
</Nodes>
|
||||
</TreeNode>
|
||||
</Nodes>
|
||||
</TreeNode>
|
||||
<TreeNode Title="parent 2" Key="0-1" Icon="carry-out" TItem="string">
|
||||
<Nodes>
|
||||
<TreeNode Title="parent 2-0" Key="0-1-0" Icon="carry-out" TItem="string">
|
||||
<Nodes>
|
||||
<TreeNode Title="leaf" Key="0-1-0-0" Icon="carry-out" TItem="string" />
|
||||
<TreeNode Title="leaf" Key="0-1-0-1" Icon="carry-out" TItem="string" />
|
||||
</Nodes>
|
||||
</TreeNode>
|
||||
</Nodes>
|
||||
</TreeNode>
|
||||
</Nodes>
|
||||
</Tree>
|
||||
<Tree ShowLine="@_showLine"
|
||||
ShowIcon="@_showIcon"
|
||||
ShowLeafIcon="@_showLeafIcon"
|
||||
DefaultExpandedKeys="@(new[]{"0-0-0"})"
|
||||
OnSelect="OnSelect"
|
||||
TItem="string">
|
||||
<TreeNode Title="parent 1" Key="0-0" Icon="carry-out" TItem="string">
|
||||
<TreeNode Title="parent 1-0" Key="0-0-0" Icon="carry-out" TItem="string">
|
||||
<TreeNode Title="leaf" Key="0-0-0-0" Icon="carry-out" TItem="string" />
|
||||
<TreeNode Key="0-0-0-1" Icon="carry-out" TItem="string">
|
||||
<TitleTemplate>
|
||||
<div>
|
||||
<div>multiple line title</div>
|
||||
<div>multiple line title</div>
|
||||
</div>
|
||||
</TitleTemplate>
|
||||
</TreeNode>
|
||||
<TreeNode Title="leaf" Key="0-0-0-2" Icon="carry-out" TItem="string" />
|
||||
</TreeNode>
|
||||
<TreeNode Title="parent 1-1" Key="0-0-1" Icon="carry-out" TItem="string">
|
||||
<TreeNode Title="left" Key="0-0-1-0" Icon="carry-out" TItem="string" />
|
||||
</TreeNode>
|
||||
<TreeNode Title="parent 1-2" Key="0-0-2" Icon="carry-out" TItem="string">
|
||||
<TreeNode Title="leaf" Key="0-0-2-0" Icon="carry-out" TItem="string" />
|
||||
<TreeNode Title="leaf" Key="0-0-2-1" Icon="carry-out" TItem="string" SwitcherIcon="form" />
|
||||
</TreeNode>
|
||||
</TreeNode>
|
||||
<TreeNode Title="parent 2" Key="0-1" Icon="carry-out" TItem="string">
|
||||
<TreeNode Title="parent 2-0" Key="0-1-0" Icon="carry-out" TItem="string">
|
||||
<TreeNode Title="leaf" Key="0-1-0-0" Icon="carry-out" TItem="string" />
|
||||
<TreeNode Title="leaf" Key="0-1-0-1" Icon="carry-out" TItem="string" />
|
||||
</TreeNode>
|
||||
</TreeNode>
|
||||
</Tree>
|
||||
</div>
|
||||
|
||||
@code {
|
||||
bool _showLine = true;
|
||||
bool _showIcon = false;
|
||||
bool _showLeafIcon = true;
|
||||
bool _showLine = true;
|
||||
bool _showIcon = false;
|
||||
bool _showLeafIcon = true;
|
||||
|
||||
void OnSelect(TreeEventArgs<string> e)
|
||||
{
|
||||
Console.WriteLine(JsonSerializer.Serialize(e));
|
||||
}
|
||||
void OnSelect(TreeEventArgs<string> e)
|
||||
{
|
||||
Console.WriteLine(JsonSerializer.Serialize(e));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user