diff --git a/.github/workflows/nightly-build.yml b/.github/workflows/nightly-build.yml index 52b84d2585..3242a1a8eb 100644 --- a/.github/workflows/nightly-build.yml +++ b/.github/workflows/nightly-build.yml @@ -82,6 +82,7 @@ jobs: echo "Version: ${FULL_VERSION}" echo "::set-output name=package_version::${FULL_VERSION}" dotnet pack components/AntDesign.csproj /p:PackageVersion=${FULL_VERSION} -c Release -o publish + dotnet pack tests/AntDesign.TestKit/AntDesign.TestKit.csproj /p:PackageVersion=${FULL_VERSION} -c Release -o publish env: next_version: ${{ steps.get_next_version.outputs.next_version }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 217380b770..455f13c9ed 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -39,6 +39,7 @@ jobs: npm install dotnet build dotnet pack components/AntDesign.csproj /p:PackageVersion=$VERSION -c Release -o publish + dotnet pack tests/AntDesign.TestKit/AntDesign.TestKit.csproj /p:PackageVersion=$VERSION -c Release -o publish dotnet nuget push publish/*.nupkg -s https://api.nuget.org/v3/index.json -k $NUGET_API_KEY --skip-duplicate - name: Publish Docs 🎉 diff --git a/.gitignore b/.gitignore index 3283d44a28..992141dad2 100644 --- a/.gitignore +++ b/.gitignore @@ -340,7 +340,7 @@ ASALocalRun/ healthchecksdb package-lock.json /components/wwwroot/less -/components/wwwroot/css/ant-design-blazor.css +/components/wwwroot/css /components/wwwroot/js/ant-design-blazor.js /components/wwwroot/js/ant-design-blazor.js.map /components/AntDesign.xml @@ -350,3 +350,4 @@ package-lock.json /AntDesign.Docs/wwwroot/docs coverage.cobertura.xml scripts/previewEditor/index.html +/site/AntDesign.Docs/wwwroot/css diff --git a/AntDesign.sln b/AntDesign.sln index 8e8ad49280..20b621c30a 100644 --- a/AntDesign.sln +++ b/AntDesign.sln @@ -29,7 +29,11 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AntDesign.Docs.Build.CLI", EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "hosts", "hosts", "{752F5AE8-BA08-4C41-B9B2-D2ED12727E63}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AntDesign.Tests", "tests\AntDesign.Tests.csproj", "{B2DC89BD-838C-459C-A32A-98F877479988}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AntDesign.TestKit", "tests\AntDesign.TestKit\AntDesign.TestKit.csproj", "{7193BE83-12C1-4B35-8197-C28D20FBA1E6}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AntDesign.Tests", "tests\AntDesign.Tests\AntDesign.Tests.csproj", "{51D7507D-48BA-43BB-8223-CE35A2D7D0D8}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{DFD13180-D1BF-44DA-BEBE-4A54EFDEFFE2}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -61,10 +65,14 @@ Global {5A765767-0766-433D-B78D-97D8F29CA6A6}.Debug|Any CPU.Build.0 = Debug|Any CPU {5A765767-0766-433D-B78D-97D8F29CA6A6}.Release|Any CPU.ActiveCfg = Release|Any CPU {5A765767-0766-433D-B78D-97D8F29CA6A6}.Release|Any CPU.Build.0 = Release|Any CPU - {B2DC89BD-838C-459C-A32A-98F877479988}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B2DC89BD-838C-459C-A32A-98F877479988}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B2DC89BD-838C-459C-A32A-98F877479988}.Release|Any CPU.ActiveCfg = Release|Any CPU - {B2DC89BD-838C-459C-A32A-98F877479988}.Release|Any CPU.Build.0 = Release|Any CPU + {7193BE83-12C1-4B35-8197-C28D20FBA1E6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7193BE83-12C1-4B35-8197-C28D20FBA1E6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7193BE83-12C1-4B35-8197-C28D20FBA1E6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7193BE83-12C1-4B35-8197-C28D20FBA1E6}.Release|Any CPU.Build.0 = Release|Any CPU + {51D7507D-48BA-43BB-8223-CE35A2D7D0D8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {51D7507D-48BA-43BB-8223-CE35A2D7D0D8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {51D7507D-48BA-43BB-8223-CE35A2D7D0D8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {51D7507D-48BA-43BB-8223-CE35A2D7D0D8}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -76,7 +84,8 @@ Global {B8761D43-B253-49FC-B144-A6CCB061951B} = {752F5AE8-BA08-4C41-B9B2-D2ED12727E63} {3F5C09C7-81EB-461C-8E0E-538D3FBAB931} = {752F5AE8-BA08-4C41-B9B2-D2ED12727E63} {5A765767-0766-433D-B78D-97D8F29CA6A6} = {D34F1DE5-ECF7-4CF0-8325-B7A38F41D376} - {B2DC89BD-838C-459C-A32A-98F877479988} = {C60BCE84-4AF4-4393-8D3E-1B69E29549C1} + {7193BE83-12C1-4B35-8197-C28D20FBA1E6} = {DFD13180-D1BF-44DA-BEBE-4A54EFDEFFE2} + {51D7507D-48BA-43BB-8223-CE35A2D7D0D8} = {DFD13180-D1BF-44DA-BEBE-4A54EFDEFFE2} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {E124DDCB-1F8D-4F96-BF41-D87019D0A412} diff --git a/components/AntDesign.csproj b/components/AntDesign.csproj index 150fbc3968..7965e8bbdc 100644 --- a/components/AntDesign.csproj +++ b/components/AntDesign.csproj @@ -54,7 +54,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/components/alert/Alert.razor b/components/alert/Alert.razor index 1f56aeed51..ef3569babb 100644 --- a/components/alert/Alert.razor +++ b/components/alert/Alert.razor @@ -4,7 +4,7 @@ @if (!_isClosed) {
- @if (ShowIcon) + @if (IsShowIcon) { @if (Icon != null) { @@ -18,18 +18,23 @@ } }
- @if (!string.IsNullOrEmpty(Message)) + @if (MessageTemplate != null) { -
@Message
+
@MessageTemplate
} - @if (!string.IsNullOrEmpty(Description)) + else if (!string.IsNullOrEmpty(Message)) { -
@Description
+
@Message
} + @if (ChildContent != null) {
@ChildContent
} + else if (!string.IsNullOrEmpty(Description)) + { +
@Description
+ }
@if (Closable) { @@ -45,4 +50,4 @@ }
-} +} \ No newline at end of file diff --git a/components/alert/Alert.razor.cs b/components/alert/Alert.razor.cs index cc50c68e3f..cb1d628ece 100644 --- a/components/alert/Alert.razor.cs +++ b/components/alert/Alert.razor.cs @@ -2,6 +2,7 @@ using AntDesign.JsInterop; using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components.Web; +using System.Collections.Generic; namespace AntDesign { @@ -52,17 +53,20 @@ public partial class Alert : AntDomComponentBase [Parameter] public string Message { get; set; } + [Parameter] + public RenderFragment MessageTemplate { get; set; } + /// /// Whether to show icon. /// [Parameter] - public bool ShowIcon { get; set; } + public bool? ShowIcon { get; set; } /// /// Type of Alert styles, options: success, info, warning, error /// [Parameter] - public string Type { get; set; } = AlertType.Default; + public string Type { get; set; } /// /// Callback when Alert is closed. @@ -79,11 +83,14 @@ public partial class Alert : AntDomComponentBase /// /// Icon to show. /// - protected string IconType => - Type == AlertType.Success ? "check-circle" - : Type == AlertType.Info ? "info-circle" - : Type == AlertType.Warning ? "exclamation-circle" - : Type == AlertType.Error ? "close-circle" : null; + protected string IconType => CalcType switch + { + AlertType.Success => "check-circle", + AlertType.Info => "info-circle", + AlertType.Warning => "exclamation-circle", + AlertType.Error => "close-circle", + _ => "exclamation-circle", + }; /// /// Indicator if the component is closed or not. @@ -101,22 +108,27 @@ public partial class Alert : AntDomComponentBase private string _innerStyle = string.Empty; + private bool IsShowIcon => (Banner && ShowIcon == null) ? true : ShowIcon == true; + + private string CalcType => Type ?? (Banner ? AlertType.Warning : AlertType.Info); + /// /// Sets the default classes. /// private void SetClassMap() { string prefixName = "ant-alert"; - ClassMapper.Clear() + ClassMapper .Add("ant-alert") - .If($"{prefixName}-{Type}", () => !string.IsNullOrEmpty(Type)) - .If($"{prefixName}-no-icon", () => !ShowIcon) + .GetIf(() => $"{prefixName}-{CalcType}", () => !string.IsNullOrEmpty(CalcType)) + .If($"{prefixName}-no-icon", () => !IsShowIcon) .If($"{prefixName}-closable", () => Closable) .If($"{prefixName}-banner", () => Banner) .If($"{prefixName}-with-description", () => !string.IsNullOrEmpty(Description) || ChildContent != null) .If($"{prefixName}-motion", () => _isClosing) .If($"{prefixName}-motion-leave", () => _isClosing) .If($"{prefixName}-motion-leave-active", () => _isClosing && _motionStage == 1) + .If($"{prefixName}-rtl", () => RTL) ; } @@ -127,11 +139,6 @@ protected override void OnInitialized() { base.OnInitialized(); - if (Banner && string.IsNullOrEmpty(Type) && Icon == null) - { - ShowIcon = false; - } - SetClassMap(); } diff --git a/components/anchor/Anchor.razor b/components/anchor/Anchor.razor index 2c033fdd56..3974cf56b8 100644 --- a/components/anchor/Anchor.razor +++ b/components/anchor/Anchor.razor @@ -2,7 +2,7 @@ @inherits AntDomComponentBase
-
+
diff --git a/components/anchor/Anchor.razor.cs b/components/anchor/Anchor.razor.cs index 8268bb74e5..7d485b58e7 100644 --- a/components/anchor/Anchor.razor.cs +++ b/components/anchor/Anchor.razor.cs @@ -14,7 +14,7 @@ namespace AntDesign public partial class Anchor : AntDomComponentBase, IAnchor { private string _ballClass = "ant-anchor-ink-ball"; - private string _ballStyle = string.Empty; + private string _ballStyle = string.Empty; private ElementReference _ink; private DomRect _selfDom; private AnchorLink _activeLink; @@ -112,6 +112,15 @@ public string Key #endregion Parameters + protected override void OnInitialized() + { + base.OnInitialized(); + + string prefixCls = "ant-anchor"; + ClassMapper.Add(prefixCls) + .If($"{prefixCls}-rtl", () => RTL); + } + protected override async Task OnAfterRenderAsync(bool firstRender) { await base.OnAfterRenderAsync(firstRender); @@ -226,7 +235,7 @@ private async void OnScroll(JsonElement obj) string activeKey = _linkTops.Where(p => (int)p.Value <= 0).OrderBy(p => p.Value).LastOrDefault().Key; if (!string.IsNullOrEmpty(activeKey)) { - _activeLink = _flatLinks.Single(l => l.Href == activeKey); + _activeLink = _flatLinks.FirstOrDefault(l => l.Href == activeKey); await ActivateAsync(_activeLink, true); } @@ -250,7 +259,10 @@ private async void OnScroll(JsonElement obj) private async Task ActivateAsync(AnchorLink anchorLink, bool active) { - anchorLink.Activate(active); + if (anchorLink == null) + return; + + anchorLink?.Activate(active); if (active && _activeLink != _lastActiveLink) { diff --git a/components/ant-design-blazor.aliyun.less b/components/ant-design-blazor.aliyun.less new file mode 100644 index 0000000000..2c74e91d8f --- /dev/null +++ b/components/ant-design-blazor.aliyun.less @@ -0,0 +1,3 @@ +@import "./style/aliyun.less"; +@import "./style/entry.less"; +@import "./components.less"; diff --git a/components/ant-design-blazor.compact.less b/components/ant-design-blazor.compact.less new file mode 100644 index 0000000000..cbca162635 --- /dev/null +++ b/components/ant-design-blazor.compact.less @@ -0,0 +1,3 @@ +@import "./style/compact.less"; +@import "./style/entry.less"; +@import "./components.less"; diff --git a/components/ant-design-blazor.dark.less b/components/ant-design-blazor.dark.less new file mode 100644 index 0000000000..9e5bcd9f8e --- /dev/null +++ b/components/ant-design-blazor.dark.less @@ -0,0 +1,3 @@ +@import "./style/dark.less"; +@import "./style/entry.less"; +@import "./components.less"; diff --git a/components/avatar/AvatarGroup.razor b/components/avatar/AvatarGroup.razor index 43592e3b89..48ac4e4ace 100644 --- a/components/avatar/AvatarGroup.razor +++ b/components/avatar/AvatarGroup.razor @@ -2,15 +2,15 @@ @inherits AntDomComponentBase -
+
@ChildContent @if (_overflow) { - + OverlayClassName="@_popoverClassMapper.Class"> @ChildContent diff --git a/components/avatar/AvatarGroup.razor.cs b/components/avatar/AvatarGroup.razor.cs index 9c62b17006..03a023b7ff 100644 --- a/components/avatar/AvatarGroup.razor.cs +++ b/components/avatar/AvatarGroup.razor.cs @@ -17,12 +17,27 @@ public partial class AvatarGroup : AntDomComponentBase [Parameter] public PlacementType MaxPopoverPlacement { get; set; } = PlacementType.Top; + private ClassMapper _popoverClassMapper = new ClassMapper(); + private bool _overflow; private string _prefixCls = "ant-avatar-group"; private IList _shownAvatarList = new List(); private IList _hiddenAvatarList = new List(); + protected override void OnInitialized() + { + base.OnInitialized(); + + ClassMapper + .Add(_prefixCls) + .If($"{_prefixCls}-rtl", () => RTL); + + _popoverClassMapper + .Add($"{_prefixCls}-popover") + .If($"{_prefixCls}-popover-rtl", () => RTL); + } + internal void AddAvatar(Avatar item) { if (item.Position == null) diff --git a/components/badge/Badge.razor.cs b/components/badge/Badge.razor.cs index 76681fa5c3..325f7c44d0 100644 --- a/components/badge/Badge.razor.cs +++ b/components/badge/Badge.razor.cs @@ -145,6 +145,7 @@ private void SetClassMap() .Add(prefixName) .If($"{prefixName}-status", () => HasStatusOrColor) .If($"{prefixName}-not-a-wrapper", () => ChildContent == null) + .If($"{prefixName}-rtl", () => RTL) ; CountClassMapper.Clear() diff --git a/components/badge/BadgeRibbon.razor.cs b/components/badge/BadgeRibbon.razor.cs index a828f161af..299e516a1f 100644 --- a/components/badge/BadgeRibbon.razor.cs +++ b/components/badge/BadgeRibbon.razor.cs @@ -35,7 +35,6 @@ public partial class BadgeRibbon : AntDomComponentBase [Parameter] public RenderFragment ChildContent { get; set; } - private string PresetColor => Color.IsIn(_badgePresetColors) ? Color : null; private string _colorStyle; @@ -51,12 +50,11 @@ private void SetClassMap() ClassMapper.Clear() .Add(prefixName) .Add($"{prefixName}-placement-{Placement}") - //.If($"{prefixName}-rtl", () => Direction == "RTL" # Placeholder for when RTL support is added + .If($"{prefixName}-rtl", () => RTL) .If($"{prefixName}-color-{PresetColor}", () => Color.IsIn(_badgePresetColors)) ; } - private void SetStyle() { if (PresetColor == null && !string.IsNullOrWhiteSpace(Color)) diff --git a/components/breadcrumb/Breadcrumb.razor.cs b/components/breadcrumb/Breadcrumb.razor.cs index cdca073bc0..8ddc2c5de8 100644 --- a/components/breadcrumb/Breadcrumb.razor.cs +++ b/components/breadcrumb/Breadcrumb.razor.cs @@ -30,7 +30,11 @@ private void Navigate(string url) protected override void OnInitialized() { - this.ClassMapper.Add("ant-breadcrumb"); + string prefixCls = "ant-breadcrumb"; + + this.ClassMapper + .Add(prefixCls) + .If($"{prefixCls}-rtl", () => RTL); base.OnInitialized(); } diff --git a/components/button/Button.razor.cs b/components/button/Button.razor.cs index eb5ff43ecc..b12aeda019 100644 --- a/components/button/Button.razor.cs +++ b/components/button/Button.razor.cs @@ -89,10 +89,10 @@ public string FormSize protected void SetClassMap() { - const string prefixName = "ant-btn"; + var prefixName = "ant-btn"; ClassMapper.Clear() - .Add("ant-btn") + .Add(prefixName) .GetIf(() => $"{prefixName}-{this.Type}", () => !string.IsNullOrEmpty(Type)) .If($"{prefixName}-dangerous", () => Danger) .GetIf(() => $"{prefixName}-{Shape}", () => !string.IsNullOrEmpty(Shape)) @@ -103,6 +103,7 @@ protected void SetClassMap() .If($"{prefixName}-background-ghost", () => Ghost) .If($"{prefixName}-block", () => this.Block) .If($"ant-input-search-button", () => this.Search) + .If($"{prefixName}-rtl", () => RTL) ; } diff --git a/components/button/ButtonGroup.razor.cs b/components/button/ButtonGroup.razor.cs index 8b0759728a..59d271551d 100644 --- a/components/button/ButtonGroup.razor.cs +++ b/components/button/ButtonGroup.razor.cs @@ -16,7 +16,6 @@ public string Size set { this._size = value; - SetClassMap(); } } @@ -25,10 +24,11 @@ public string Size private void SetClassMap() { string prefixName = "ant-btn-group"; - ClassMapper.Clear().Add(prefixName) + ClassMapper.Add(prefixName) .If("ant-dropdown-button", () => _isInDropdown) .If($"{prefixName}-lg", () => this._size == "large") - .If($"{prefixName}-sm", () => this._size == "small"); + .If($"{prefixName}-sm", () => this._size == "small") + .If($"{prefixName}-rtl", () => RTL); } protected override void OnInitialized() diff --git a/components/calendar/Calendar.razor.cs b/components/calendar/Calendar.razor.cs index 4a17b257c1..733f487c6e 100644 --- a/components/calendar/Calendar.razor.cs +++ b/components/calendar/Calendar.razor.cs @@ -114,6 +114,7 @@ protected void SetClass() this.ClassMapper.Clear() .Add(PrefixCls) .If($"{PrefixCls}-full", () => FullScreen) + .If($"{PrefixCls}-rtl", () => RTL) ; } diff --git a/components/carousel/Carousel.razor.cs b/components/carousel/Carousel.razor.cs index 8f23123fe2..4e511f725d 100644 --- a/components/carousel/Carousel.razor.cs +++ b/components/carousel/Carousel.razor.cs @@ -11,6 +11,7 @@ namespace AntDesign public partial class Carousel : AntDomComponentBase { private const string PrefixCls = "ant-carousel"; + private string TrackStyle { get @@ -35,8 +36,9 @@ private string TrackStyle return string.Empty; } } + internal string SlickClonedStyle => $"width: {SlickWidth}px;"; - private string SlickListStyle => IsHorizontal ? string.Empty : $"height: {SlickHeight}px"; + private string SlickListStyle => IsHorizontal ? string.Empty : $"height: {SlickHeight}px"; internal int SlickWidth { get; set; } = -1; private int SlickHeight { get; set; } = -1; private int TotalWidth => SlickWidth * (_slicks.Count * 2 + 1); @@ -100,7 +102,8 @@ private void SetClass() ClassMapper.Clear() .Add(PrefixCls) - .If($"{PrefixCls}-vertical", () => !IsHorizontal); + .If($"{PrefixCls}-vertical", () => !IsHorizontal) + .If($"{PrefixCls}-rtl", () => RTL); ; } protected override void OnParametersSet() diff --git a/components/carousel/style/index.less b/components/carousel/style/index.less index 91852431b1..d60c05c960 100644 --- a/components/carousel/style/index.less +++ b/components/carousel/style/index.less @@ -185,6 +185,7 @@ } &-top { top: 12px; + bottom: auto; } li { position: relative; diff --git a/components/cascader/Cascader.razor b/components/cascader/Cascader.razor index 3d0fef03e7..6247948d11 100644 --- a/components/cascader/Cascader.razor +++ b/components/cascader/Cascader.razor @@ -26,7 +26,7 @@
-
    +
      @foreach (CascaderNode nd in _nodelist) { bool isActive = _renderNodes.Where(n => n == nd).Any(); diff --git a/components/cascader/Cascader.razor.cs b/components/cascader/Cascader.razor.cs index 02810af345..a219146770 100644 --- a/components/cascader/Cascader.razor.cs +++ b/components/cascader/Cascader.razor.cs @@ -3,6 +3,7 @@ using Microsoft.AspNetCore.Components; using System.Linq; using System.Collections; +using System.Threading.Tasks; namespace AntDesign { @@ -98,6 +99,9 @@ public IReadOnlyCollection Options ///
internal List _renderNodes = new List(); + private ClassMapper _menuClassMapper = new ClassMapper(); + private ClassMapper _inputClassMapper = new ClassMapper(); + /// /// 浮层 展开/折叠状态 /// @@ -114,10 +118,9 @@ public IReadOnlyCollection Options ///
private SelectedTypeEnum SelectedType { get; set; } - private ClassMapper _inputClassMapper = new ClassMapper(); private string _displayText; - private static Hashtable _sizeMap = new Hashtable() + private static Dictionary _sizeMap = new Dictionary() { ["large"] = "lg", ["small"] = "sm" @@ -127,15 +130,27 @@ protected override void OnInitialized() { base.OnInitialized(); - ClassMapper.Add("ant-cascader-picker") + ClassMapper + .Add("ant-cascader-picker") .GetIf(() => $"ant-cascader-picker-{Size}", () => _sizeMap.ContainsKey(Size)) - .GetIf(() => $"ant-input-{_sizeMap[Size]}", () => _sizeMap.ContainsKey(Size)) - ; + .If("ant-cascader-picker-rtl", () => RTL); _inputClassMapper .Add("ant-input") .Add("ant-cascader-input") - .GetIf(() => $"ant-input-{_sizeMap[Size]}", () => _sizeMap.ContainsKey(Size)); + .GetIf(() => $"ant-cascader-input-{_sizeMap[Size]}", () => _sizeMap.ContainsKey(Size)) + .If("ant-cascader-input-rtl", () => RTL); + + _menuClassMapper + .Add("ant-cascader-menu") + .If($"ant-cascader-menu-rtl", () => RTL); + } + + protected override void OnParametersSet() + { + base.OnParametersSet(); + + ProcessParentAndDefault(); } protected override void OnValueChange(string value) diff --git a/components/checkbox/Checkbox.razor.cs b/components/checkbox/Checkbox.razor.cs index 6183175ffa..6cc245976e 100644 --- a/components/checkbox/Checkbox.razor.cs +++ b/components/checkbox/Checkbox.razor.cs @@ -68,14 +68,15 @@ protected void SetClass() string prefixName = "ant-checkbox"; ClassMapper.Clear() .Add(prefixName) - .If($"{prefixName}-wrapper", () => true) + .Add($"{prefixName}-wrapper") .If($"{prefixName}-wrapper-checked", () => Checked); ClassMapperSpan.Clear() .Add(prefixName) .If($"{prefixName}-checked", () => Checked && !Indeterminate) .If($"{prefixName}-disabled", () => Disabled) - .If($"{prefixName}-indeterminate", () => Indeterminate); + .If($"{prefixName}-indeterminate", () => Indeterminate) + .If($"{prefixName}-rtl", () => RTL); } protected override void OnValueChange(bool value) diff --git a/components/checkbox/CheckboxGroup.razor.cs b/components/checkbox/CheckboxGroup.razor.cs index 1806cf3ff4..11df176f02 100644 --- a/components/checkbox/CheckboxGroup.razor.cs +++ b/components/checkbox/CheckboxGroup.razor.cs @@ -26,7 +26,9 @@ public partial class CheckboxGroup : AntInputComponentBase public CheckboxGroup() { - ClassMapper.Add("ant-checkbox-group"); + ClassMapper + .Add("ant-checkbox-group") + .If("ant-checkbox-group-rtl", () => RTL); } internal void AddItem(Checkbox checkbox) diff --git a/components/checkbox/style/mixin.less b/components/checkbox/style/mixin.less index 990fcd79dd..ef8262ce1d 100644 --- a/components/checkbox/style/mixin.less +++ b/components/checkbox/style/mixin.less @@ -7,11 +7,9 @@ .reset-component(); position: relative; - top: -0.09em; - display: inline-block; + top: 0.2em; line-height: 1; white-space: nowrap; - vertical-align: middle; outline: none; cursor: pointer; @@ -148,13 +146,15 @@ .@{checkbox-prefix-cls}-wrapper { .reset-component(); - - display: inline-block; + display: inline-flex; + align-items: baseline; line-height: unset; cursor: pointer; + &.@{checkbox-prefix-cls}-wrapper-disabled { cursor: not-allowed; } + & + & { margin-left: 8px; } @@ -167,10 +167,9 @@ .@{checkbox-prefix-cls}-group { .reset-component(); - display: inline-block; + &-item { - display: inline-block; margin-right: @checkbox-group-item-margin-right; &:last-child { margin-right: 0; diff --git a/components/collapse/Collapse.razor.cs b/components/collapse/Collapse.razor.cs index 14f3c799a7..09b6c0ccd1 100644 --- a/components/collapse/Collapse.razor.cs +++ b/components/collapse/Collapse.razor.cs @@ -41,10 +41,12 @@ public partial class Collapse : AntDomComponentBase private void SetClassMap() { - ClassMapper.Clear().Add("ant-collapse") + ClassMapper + .Add("ant-collapse") .If("ant-collapse-icon-position-left", () => ExpandIconPosition == CollapseExpandIconPosition.Left) .If("ant-collapse-icon-position-right", () => ExpandIconPosition == CollapseExpandIconPosition.Right) - .If("ant-collapse-borderless", () => !this.Bordered); + .If("ant-collapse-borderless", () => !this.Bordered) + .If("ant-collapse-rtl", () => RTL); ; } protected override async Task OnInitializedAsync() diff --git a/components/comment/Comment.razor.cs b/components/comment/Comment.razor.cs index 1db3baea65..4c52036e12 100644 --- a/components/comment/Comment.razor.cs +++ b/components/comment/Comment.razor.cs @@ -43,7 +43,8 @@ protected override void OnInitialized() { base.OnInitialized(); this.ClassMapper.Clear() - .Add("ant-comment"); + .Add("ant-comment") + .If("ant-comment-rtl", () => RTL); } } } diff --git a/components/config-provider/ConfigProvider.razor b/components/config-provider/ConfigProvider.razor new file mode 100644 index 0000000000..00b2293b09 --- /dev/null +++ b/components/config-provider/ConfigProvider.razor @@ -0,0 +1,7 @@ +@namespace AntDesign +@inherits AntComponentBase + + + @ChildContent + + diff --git a/components/config-provider/ConfigProvider.razor.cs b/components/config-provider/ConfigProvider.razor.cs new file mode 100644 index 0000000000..22977e3edb --- /dev/null +++ b/components/config-provider/ConfigProvider.razor.cs @@ -0,0 +1,57 @@ +using System.Threading.Tasks; +using Microsoft.AspNetCore.Components; + +namespace AntDesign +{ + public partial class ConfigProvider : AntComponentBase + { + [Parameter] + public string Direction + { + get => _direction; + set + { + if (_direction != value) + { + _direction = value; + _waitingDirectionUpdate = true; + } + } + } + + [Parameter] public RenderFragment ChildContent { get; set; } + + [Inject] public ConfigService ConfigService { get; set; } + + private string _direction; + + private bool _waitingDirectionUpdate; + private bool _afterFirstRender; + + protected override async Task OnAfterRenderAsync(bool firstRender) + { + await base.OnAfterRenderAsync(firstRender); + + if (firstRender) + { + _afterFirstRender = true; + } + + if (_afterFirstRender) + { + if (_waitingDirectionUpdate) + { + _waitingDirectionUpdate = false; + await ChangeDirection(_direction); + } + } + } + + public async Task ChangeDirection(string direction) + { + _direction = direction?.ToUpperInvariant(); + await ConfigService.ChangeDirection(_direction); + await InvokeAsync(StateHasChanged); + } + } +} diff --git a/components/config-provider/ConfigService.cs b/components/config-provider/ConfigService.cs new file mode 100644 index 0000000000..a5289737ea --- /dev/null +++ b/components/config-provider/ConfigService.cs @@ -0,0 +1,27 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using Microsoft.JSInterop; + +namespace AntDesign +{ + public class ConfigService + { + private IJSRuntime _jS; + + public ConfigService(IJSRuntime js) + { + _jS = js; + } + + public async Task ChangeDirection(string direction) + { + direction = direction?.ToLowerInvariant(); + await _jS.InvokeVoidAsync(JSInteropConstants.SetDomAttribute, "html", new Dictionary + { + ["class"] = direction, + ["data-direction"] = direction + }); + + } + } +} diff --git a/components/core/Base/AntDomComponentBase.cs b/components/core/Base/AntDomComponentBase.cs index 7e8c0fddf1..85b3182019 100644 --- a/components/core/Base/AntDomComponentBase.cs +++ b/components/core/Base/AntDomComponentBase.cs @@ -10,6 +10,11 @@ public abstract class AntDomComponentBase : AntComponentBase [Parameter] public string Id { get; set; } + [CascadingParameter] + public ConfigProvider ConfigProvider { get; set; } + + protected bool RTL => ConfigProvider?.Direction == "RTL"; + //[Parameter(CaptureUnmatchedValues = true)] //public Dictionary Attributes { get; set; } = new Dictionary(); diff --git a/components/core/Base/TemplateComponentBase.cs b/components/core/Base/TemplateComponentBase.cs index efb5bef827..e06b07e7f0 100644 --- a/components/core/Base/TemplateComponentBase.cs +++ b/components/core/Base/TemplateComponentBase.cs @@ -1,10 +1,16 @@ using System; using System.Collections.Generic; +using System.ComponentModel; using System.Text; +using System.Threading.Tasks; using Microsoft.AspNetCore.Components; namespace AntDesign { + /// + /// + /// + /// public abstract class TemplateComponentBase : AntComponentBase { /// diff --git a/components/core/CloseEventArgs.cs b/components/core/CloseEventArgs.cs new file mode 100644 index 0000000000..ad31feb16b --- /dev/null +++ b/components/core/CloseEventArgs.cs @@ -0,0 +1,29 @@ +// 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 +{ + /// + /// Can be used to conditionally block closing events + /// + /// + public class CloseEventArgs where T : EventArgs + { + public CloseEventArgs(T eventArgs) + { + EventArgs = eventArgs; + } + + public T EventArgs { get; set; } + + /// + /// If true, the component will be prevented from closing + /// + public bool Cancel { get; set; } + } +} diff --git a/components/core/Component/overlay/Overlay.razor b/components/core/Component/overlay/Overlay.razor index 176559e244..7d0560895c 100644 --- a/components/core/Component/overlay/Overlay.razor +++ b/components/core/Component/overlay/Overlay.razor @@ -6,7 +6,7 @@ string display = GetDisplayStyle(); string overlayCls = GetOverlayCls(); -
+ { + public static readonly DirectionVHType Vertical = new DirectionVHType(nameof(Vertical), 0); + public static readonly DirectionVHType Horizontal = new DirectionVHType(nameof(Horizontal), 1); + + private DirectionVHType(string name, int value) : base(name, value) + { + } + } +} diff --git a/components/core/EventUtil.cs b/components/core/EventUtil.cs new file mode 100644 index 0000000000..78158a9548 --- /dev/null +++ b/components/core/EventUtil.cs @@ -0,0 +1,89 @@ +// 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.Threading.Tasks; +using Microsoft.AspNetCore.Components; + +namespace AntDesign +{ + /// + /// avoid component re-rendering caused by events to Blazor components.(pure event handlers) + /// + /// author: SteveSandersonMS, from . + /// + /// + /// issue: . + /// + /// + public static class EventUtil + { + // The repetition in here is because of the four combinations of handlers (sync/async * with/without arg) + public static Action AsNonRenderingEventHandler(Action callback) + => new SyncReceiver(callback).Invoke; + public static Action AsNonRenderingEventHandler(Action callback) + => new SyncReceiver(callback).Invoke; + public static Func AsNonRenderingEventHandler(Func callback) + => new AsyncReceiver(callback).Invoke; + public static Func AsNonRenderingEventHandler(Func callback) + => new AsyncReceiver(callback).Invoke; + + // By implementing IHandleEvent, we can override the event handling logic on a per-handler basis + // The logic here just calls the callback without triggering any re-rendering + class ReceiverBase : IHandleEvent + { + public Task HandleEventAsync(EventCallbackWorkItem item, object arg) => item.InvokeAsync(arg); + } + + + class SyncReceiver : ReceiverBase + { + private Action callback; + + public SyncReceiver(Action callback) + { + this.callback = callback; + } + + public void Invoke() => callback(); + } + + class SyncReceiver : ReceiverBase + { + private Action callback; + + public SyncReceiver(Action callback) + { + this.callback = callback; + } + + public void Invoke(T arg) => callback(arg); + } + + class AsyncReceiver : ReceiverBase + { + private Func callback; + + public AsyncReceiver(Func callback) + { + this.callback = callback; + } + + public Task Invoke() => callback(); + } + + class AsyncReceiver: ReceiverBase + { + private Func callback; + + public AsyncReceiver(Func callback) + { + this.callback = callback; + } + + public Task Invoke(T arg) => callback(arg); + } + } + +} diff --git a/components/core/Extensions/ServiceCollectionExtensions.cs b/components/core/Extensions/ServiceCollectionExtensions.cs index 0cf2447248..8aef05defc 100644 --- a/components/core/Extensions/ServiceCollectionExtensions.cs +++ b/components/core/Extensions/ServiceCollectionExtensions.cs @@ -25,6 +25,7 @@ public static IServiceCollection AddAntDesign(this IServiceCollection services) services.TryAddScoped(); services.TryAddScoped(); services.TryAddScoped(); + services.TryAddScoped(); CultureInfo.DefaultThreadCurrentUICulture = CultureInfo.CurrentCulture; diff --git a/components/core/Feedback/FeedbackComponent.cs b/components/core/Feedback/FeedbackComponent.cs new file mode 100644 index 0000000000..306b6d34ad --- /dev/null +++ b/components/core/Feedback/FeedbackComponent.cs @@ -0,0 +1,102 @@ +// 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.Diagnostics.CodeAnalysis; +using System.Text; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Components; + +namespace AntDesign +{ + /// + /// Feedback Component + /// + /// + public abstract class FeedbackComponent : TemplateComponentBase, IModalTemplate + { + private IFeedbackRef _feedbackRef; + + /// + /// The options that allow you to pass in templates from the outside + /// + [Parameter] + public IFeedbackRef FeedbackRef + { + get => _feedbackRef; + set + { + _feedbackRef = value; + _feedbackRef.ModalTemplate ??= this; + } + } + + /// + /// + /// + public IOkCancelRef OkCancelRef => FeedbackRef as IOkCancelRef; + + /// + /// In order that the user can close the template through the button + /// 为了用户可以在模板内通过按钮主动关闭 + /// + /// + public async Task CloseFeedbackAsync() + { + await (FeedbackRef?.CloseAsync() ?? Task.CompletedTask); + } + + /// + /// 在 OK 按钮触发时回调,可以用来取消关闭 + /// + /// + public virtual Task OkAsync(ModalClosingEventArgs args) + { + return OnFeedbackOkAsync(args); + } + + /// + /// 在 Cancel 按钮触发时回调,可以用来取消关闭 + /// + /// + public virtual Task CancelAsync(ModalClosingEventArgs args) + { + return OnFeedbackCancelAsync(args); + } + + + /// + /// 在 OK 按钮触发时回调,可以用来取消关闭 + /// + /// + public virtual Task OnFeedbackOkAsync(ModalClosingEventArgs args) + { + return Task.CompletedTask; + } + + /// + /// 在 Cancel 按钮触发时回调,可以用来取消关闭 + /// + /// + /// + public virtual Task OnFeedbackCancelAsync(ModalClosingEventArgs args) + { + return Task.CompletedTask; + } + } + + /// + /// Feedback Component + /// + /// + /// + public abstract class FeedbackComponent : FeedbackComponent + { + /// + /// + /// + public IOkCancelRef OkCancelRefWithResult => FeedbackRef as IOkCancelRef; + } +} diff --git a/components/core/Feedback/FeedbackRefBase.cs b/components/core/Feedback/FeedbackRefBase.cs new file mode 100644 index 0000000000..9a92c80b21 --- /dev/null +++ b/components/core/Feedback/FeedbackRefBase.cs @@ -0,0 +1,88 @@ +// 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 System.Threading.Tasks; + +namespace AntDesign +{ + /// + /// + /// + public abstract class FeedbackRefBase : IFeedbackRef + { + /// + /// + /// + IModalTemplate IFeedbackRef.ModalTemplate { get; set; } + + + /// + public Func OnOpen { get; set; } + + /// + public Func OnClose { get; set; } + + /// + /// just open close feedback component + /// + /// + public abstract Task OpenAsync(); + + + /// + public abstract Task UpdateConfigAsync(); + + /// + /// just do close feedback component, and will not trigger OkAsync or OkCancel + /// + /// + public abstract Task CloseAsync(); + + } + + /// + /// + /// + public abstract class FeedbackRefWithOkCancelBase : FeedbackRefBase, IOkCancelRef + { + /// + /// invoke when cancel button or closer click + /// + public Func OnCancel { get; set; } + + /// + /// invoke when Ok button click + /// + public Func OnOk { get; set; } + + /// + /// Ok button click + /// + /// + public async Task OkAsync(ModalClosingEventArgs e) + { + await CloseAsync(); + if (OnOk != null) + { + await OnOk(); + } + } + + /// + /// Cancel button click + /// + /// + public async Task CancelAsync(ModalClosingEventArgs e) + { + await CloseAsync(); + if (OnCancel != null) + { + await OnCancel(); + } + } + } +} diff --git a/components/core/Feedback/IFeedbackRef.cs b/components/core/Feedback/IFeedbackRef.cs new file mode 100644 index 0000000000..5186953c31 --- /dev/null +++ b/components/core/Feedback/IFeedbackRef.cs @@ -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.Text; +using System.Threading.Tasks; + +namespace AntDesign +{ + /// + /// Component reference with open and close method + /// + public interface IFeedbackRef + { + /// + /// to get feedback inner component's event + /// + internal IModalTemplate ModalTemplate { get; set; } + + /// + /// on Feedback open + /// + public Func OnOpen { get; set; } + + /// + /// on Feedback close + /// + public Func OnClose { get; set; } + + /// + /// open the component + /// + /// + public Task OpenAsync(); + + /// + /// update the component + /// + /// + public Task UpdateConfigAsync(); + + /// + /// just do close feedback component, and will not trigger OkAsync or OkCancel + /// + /// + public Task CloseAsync(); + } + + +} diff --git a/components/core/Feedback/IOkCancelRef.cs b/components/core/Feedback/IOkCancelRef.cs new file mode 100644 index 0000000000..2a098d992f --- /dev/null +++ b/components/core/Feedback/IOkCancelRef.cs @@ -0,0 +1,68 @@ +// 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 System.Threading.Tasks; + +namespace AntDesign +{ + /// + /// Component reference with Ok and Cancel method + /// + public interface IOkCancelRef : IFeedbackRef + { + /// + /// invoked when cancel button or closer click + /// + public Func OnCancel { get; set; } + + /// + /// invoked when Ok button click + /// + public Func OnOk { get; set; } + + /// + /// Trigger Ok button click + /// + /// + public Task OkAsync(ModalClosingEventArgs e); + + /// + /// Trigger Cancel button click + /// + /// + public Task CancelAsync(ModalClosingEventArgs e); + } + + /// + /// + /// + /// + public interface IOkCancelRef : IFeedbackRef + { + /// + /// invoke when cancel button or closer click + /// + public Func OnCancel { get; set; } + + /// + /// invoke when Ok button click + /// + public Func OnOk { get; set; } + + /// + /// Trigger Ok button click + /// + /// + public Task OkAsync(TResult result); + + /// + /// Trigger Cancel button click + /// + /// + public Task CancelAsync(TResult result); + } +} diff --git a/components/core/Helpers/THelper.cs b/components/core/Helpers/THelper.cs new file mode 100644 index 0000000000..1f44519a70 --- /dev/null +++ b/components/core/Helpers/THelper.cs @@ -0,0 +1,86 @@ +// 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 System.Text; + +namespace AntDesign +{ + public static class THelper + { + public static T ChangeType(object value) + { + var t = typeof(T); + + if (t.IsGenericType && t.GetGenericTypeDefinition().Equals(typeof(Nullable<>))) + { + if (value == null) + { + return default(T); + } + + t = Nullable.GetUnderlyingType(t); + } + + return (T)Convert.ChangeType(value, t); + } + public static bool IsTypeNullable() + { + return Nullable.GetUnderlyingType(typeof(T)) != null; + } + + public static Type GetNullableType() + { + Type type = typeof(T); + type = Nullable.GetUnderlyingType(type) ?? type; + if (type.IsValueType) + return typeof(Nullable<>).MakeGenericType(type); + else + return type; + } + public static Type GetUnderlyingType() + { + Type type = typeof(T); + Type targetType; + if (type.GetTypeInfo().IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)) + { + targetType = Nullable.GetUnderlyingType(type); + } + else + { + targetType = type; + } + return targetType; + } + + public static bool IsNumericType() + { + + Type type = GetUnderlyingType(); + if (type == null) + { + return false; + } + + switch (Type.GetTypeCode(type)) + { + case TypeCode.Byte: + case TypeCode.Decimal: + case TypeCode.Double: + case TypeCode.Int16: + case TypeCode.Int32: + case TypeCode.Int64: + case TypeCode.SByte: + case TypeCode.Single: + case TypeCode.UInt16: + case TypeCode.UInt32: + case TypeCode.UInt64: + return true; + } + return false; + } + } +} diff --git a/components/core/JsInterop/JSInteropConstants.cs b/components/core/JsInterop/JSInteropConstants.cs index 8ab9743d03..d4fcb7c472 100644 --- a/components/core/JsInterop/JSInteropConstants.cs +++ b/components/core/JsInterop/JSInteropConstants.cs @@ -104,6 +104,8 @@ public static class JSInteropConstants public static string DisposeResizeTextArea => $"{FUNC_PREFIX}disposeResizeTextArea"; + public static string SetDomAttribute => $"{FUNC_PREFIX}setDomAttribute"; + #region Draggable Modal public static string EnableDraggable => $"{FUNC_PREFIX}enableDraggable"; diff --git a/components/core/JsInterop/interop.ts b/components/core/JsInterop/interop.ts index 30f70b6227..2bc7e19a54 100644 --- a/components/core/JsInterop/interop.ts +++ b/components/core/JsInterop/interop.ts @@ -493,7 +493,7 @@ export function getMaxZIndex() { return [...document.all].reduce((r, e) => Math.max(r, +window.getComputedStyle(e).zIndex || 0), 0) } -export function getStyle(element, styleProp) { +export function getStyle(element, styleProp) { if (element.currentStyle) return element.currentStyle[styleProp]; else if (window.getComputedStyle) @@ -501,9 +501,9 @@ export function getStyle(element, styleProp) { } export function getTextAreaInfo(element) { - var result = {}; - var dom = getDom(element); - result["scrollHeight"] = dom.scrollHeight || 0; + var result = {}; + var dom = getDom(element); + result["scrollHeight"] = dom.scrollHeight || 0; if (element.currentStyle) { result["lineHeight"] = parseFloat(element.currentStyle["line-height"]); @@ -521,9 +521,9 @@ export function getTextAreaInfo(element) { } //Firefox can return this as NaN, so it has to be handled here like that. if (Object.is(NaN, result["borderTop"])) - result["borderTop"] = 1; + result["borderTop"] = 1; if (Object.is(NaN, result["borderBottom"])) - result["borderBottom"] = 1; + result["borderBottom"] = 1; return result; } @@ -545,7 +545,6 @@ export function disposeResizeTextArea(element) { element.removeEventListener("input", funcDict[element.id + "input"]); objReferenceDict[element.id] = null; funcDict[element.id + "input"] = null; - } export function resizeTextArea(element, minRows, maxRows) { @@ -577,8 +576,6 @@ export function resizeTextArea(element, minRows, maxRows) { } } - - const objReferenceDict = {}; export function disposeObj(objReferenceName) { delete objReferenceDict[objReferenceName]; @@ -668,4 +665,11 @@ export function removePreventEnterOnOverlayVisible(element) { (dom as HTMLElement).removeEventListener("keydown", funcDict[element.id + "keydown:Enter"]); funcDict[element.id + "keydown:Enter"] = null; } +} + +export function setDomAttribute(element, attributes) { + let dom = getDom(element); + for (var key in attributes) { + (dom as HTMLElement).setAttribute(key, attributes[key]); + } } \ No newline at end of file diff --git a/components/core/Reflection/PropertyReflector.cs b/components/core/Reflection/PropertyReflector.cs index 762f6eab8e..40d914372d 100644 --- a/components/core/Reflection/PropertyReflector.cs +++ b/components/core/Reflection/PropertyReflector.cs @@ -21,7 +21,9 @@ private PropertyReflector(PropertyInfo propertyInfo) { this.PropertyInfo = propertyInfo; this.RequiredAttribute = propertyInfo.GetCustomAttribute(true); - this.DisplayName = propertyInfo.GetCustomAttribute(true)?.DisplayName ?? propertyInfo.Name; + this.DisplayName = propertyInfo.GetCustomAttribute(true)?.DisplayName ?? + propertyInfo.GetCustomAttribute(true)?.Name ?? + propertyInfo.Name; this.PropertyName = PropertyInfo.Name; } diff --git a/components/date-picker/DatePicker.razor b/components/date-picker/DatePicker.razor index ad44c37f59..807567c78d 100644 --- a/components/date-picker/DatePicker.razor +++ b/components/date-picker/DatePicker.razor @@ -15,7 +15,7 @@ Trigger="new TriggerType[] { TriggerType.Click }">
-
+
diff --git a/components/date-picker/RangePicker.razor b/components/date-picker/RangePicker.razor index 27331814a4..554fd0f4b1 100644 --- a/components/date-picker/RangePicker.razor +++ b/components/date-picker/RangePicker.razor @@ -17,11 +17,11 @@
-
- +
+
-
- +
+
@if (RenderExtraFooter != null && !IsShowTime) diff --git a/components/date-picker/internal/DatePickerBase.cs b/components/date-picker/internal/DatePickerBase.cs index 4321fea7ab..5ef3b4ec0d 100644 --- a/components/date-picker/internal/DatePickerBase.cs +++ b/components/date-picker/internal/DatePickerBase.cs @@ -87,7 +87,8 @@ public string Picker public DatePickerLocale Locale { get { return _locale; } - set { + set + { _locale = value; _isLocaleSetOutside = true; } @@ -97,7 +98,8 @@ public DatePickerLocale Locale public CultureInfo CultureInfo { get { return _cultureInfo; } - set { + set + { _cultureInfo = value; _isCultureSetOutside = true; } @@ -163,6 +165,7 @@ public CultureInfo CultureInfo public string Format { get; set; } private TValue _defaultValue; + [Parameter] public TValue DefaultValue { @@ -172,6 +175,7 @@ public TValue DefaultValue protected bool[] UseDefaultPickerValue { get; } = new bool[2]; private TValue _defaultPickerValue; + [Parameter] public TValue DefaultPickerValue { @@ -237,6 +241,8 @@ protected DatePickerStatus[] _pickerStatus private CultureInfo _cultureInfo = LocaleProvider.CurrentLocale.CurrentCulture; private DatePickerLocale _locale = LocaleProvider.CurrentLocale.DatePicker; + protected ClassMapper _panelClassMapper = new ClassMapper(); + protected override void OnInitialized() { // set default picker type @@ -256,18 +262,12 @@ public override Task SetParametersAsync(ParameterView parameters) return base.SetParametersAsync(parameters); } - protected override void OnParametersSet() - { - this.SetClass(); - - base.OnParametersSet(); - } - protected void SetClass() { this.ClassMapper.Clear() .Add(PrefixCls) - .Add($"{PrefixCls}-{Size}") + .Get(() => $"{PrefixCls}-{Size}") + .If($"{PrefixCls}-rtl", () => RTL) .If($"{PrefixCls}-borderless", () => Bordered == false) .If($"{PrefixCls}-disabled", () => Disabled == true) .If($"{ClassName}", () => !string.IsNullOrEmpty(ClassName)) @@ -276,6 +276,10 @@ protected void SetClass() //.If($"{PrefixCls}-normal", () => Image.IsT1 && Image.AsT1 == Empty.PRESENTED_IMAGE_SIMPLE) //.If($"{PrefixCls}-{Direction}", () => Direction.IsIn("ltr", "rlt")) ; + + _panelClassMapper + .Add($"{PrefixCls}-panel") + .If($"{PrefixCls}-panel-rtl", () => RTL); } protected async override Task OnAfterRenderAsync(bool firstRender) @@ -293,7 +297,14 @@ protected async override Task OnAfterRenderAsync(bool firstRender) else if (_inputEnd.IsOnFocused) { Element element = await JsInvokeAsync(JSInteropConstants.GetDomInfo, _inputEnd.Ref); - _activeBarStyle = $"width: {element.clientWidth - 10}px; position: absolute; transform: translate3d({element.clientWidth + 16}px, 0px, 0px);"; + int translateDistance = element.clientWidth + 16; + + if (RTL) + { + translateDistance = -translateDistance; + } + + _activeBarStyle = $"width: {element.clientWidth - 10}px; position: absolute; transform: translate3d({translateDistance}px, 0px, 0px);"; _rangeArrowStyle = $"left: {element.clientWidth + 30}px"; } else @@ -481,7 +492,7 @@ public int GetOnFocusPickerIndex() } /// - /// Get pickerValue by picker index. Note that index refers to a picker panel + /// Get pickerValue by picker index. Note that index refers to a picker panel /// and not to input text. For RangePicker 2 inputs generate 2 panels. /// /// @@ -495,7 +506,7 @@ public DateTime GetIndexPickerValue(int index) } else { - //First picker panel will show the value, second panel shows next + //First picker panel will show the value, second panel shows next //expected value that depends on Picker type return Picker switch { @@ -539,7 +550,7 @@ public string GetFormatValue(DateTime value, int index) } /// - /// Changes what date(s) will be visible on the picker. + /// Changes what date(s) will be visible on the picker. /// /// New date to be saved. /// Index of the input box, where 0 = inputStart and 1 = inputEnd (only RangePicker) diff --git a/components/date-picker/internal/DatePickerMonthPanel.razor b/components/date-picker/internal/DatePickerMonthPanel.razor index 5cd26fa8ed..d064a8ed4a 100644 --- a/components/date-picker/internal/DatePickerMonthPanel.razor +++ b/components/date-picker/internal/DatePickerMonthPanel.razor @@ -14,7 +14,7 @@ string inViewClass = $"{PrefixCls}-cell-in-view"; } -
+
RTL); + } } } diff --git a/components/descriptions/Descriptions.razor.cs b/components/descriptions/Descriptions.razor.cs index 6c54fbf9b1..bcd8596676 100644 --- a/components/descriptions/Descriptions.razor.cs +++ b/components/descriptions/Descriptions.razor.cs @@ -37,7 +37,7 @@ public partial class Descriptions : AntDomComponentBase [Parameter] public bool Colon { get; set; } - #endregion Parameters + #endregion Parameters [Parameter] public RenderFragment ChildContent { get; set; } @@ -73,7 +73,9 @@ private static readonly List<(int PixelWidth, BreakpointEnum Breakpoint)> _descr private void SetClassMap() { - ClassMapper.Clear().Add("ant-descriptions") + ClassMapper + .Add("ant-descriptions") + .If("ant-descriptions", () => RTL) .If("ant-descriptions-bordered", () => this.Bordered) .If("ant-descriptions-middle", () => this.Size == DescriptionsSize.Middle) .If("ant-descriptions-small", () => this.Size == DescriptionsSize.Small); @@ -120,7 +122,6 @@ protected override async Task OnFirstAfterRenderAsync() protected override async Task OnParametersSetAsync() { - SetClassMap(); PrepareMatrix(); await InvokeAsync(StateHasChanged); await base.OnParametersSetAsync(); @@ -169,7 +170,6 @@ void FlushRow() private async Task SetRealColumn() { - if (Column.IsT0) { _realColumn = Column.AsT0 == 0 ? 3 : Column.AsT0; @@ -182,7 +182,5 @@ private async Task SetRealColumn() _realColumn = Column.AsT1.ContainsKey(bp.ToString()) ? Column.AsT1[bp.ToString()] : _defaultColumnMap[bp.ToString()]; } } - - } } diff --git a/components/divider/Divider.razor.cs b/components/divider/Divider.razor.cs index f6dfac4e65..b57180c060 100644 --- a/components/divider/Divider.razor.cs +++ b/components/divider/Divider.razor.cs @@ -16,7 +16,7 @@ public partial class Divider : AntDomComponentBase /// /// 'horizontal' | 'vertical' /// - [Parameter] public string Type { get; set; } = "horizontal"; + [Parameter] public DirectionVHType Type { get; set; } = DirectionVHType.Horizontal; /// /// 'left' | 'right' | 'center' @@ -29,7 +29,8 @@ private void SetClass() { ClassMapper.Clear() .Add("ant-divider") - .Get(() => $"ant-divider-{this.Type.ToLowerInvariant()}") + .If("ant-divider", () => RTL) + .Get(() => $"ant-divider-{this.Type.Name.ToLowerInvariant()}") .If("ant-divider-with-text", () => Text != null || ChildContent != null) .GetIf(() => $"ant-divider-with-text-{this.Orientation.ToLowerInvariant()}", () => Text != null || ChildContent != null) .If($"ant-divider-plain", () => Plain && (Text != null || ChildContent != null)) diff --git a/components/drawer/Drawer.razor.cs b/components/drawer/Drawer.razor.cs index 5c9edddecb..3271e7759d 100644 --- a/components/drawer/Drawer.razor.cs +++ b/components/drawer/Drawer.razor.cs @@ -192,6 +192,7 @@ private void SetClass() .Add(prefixCls) .If($"{prefixCls}-open", () => _isOpen) .If($"{prefixCls}-{Placement}", () => Placement.IsIn("top", "bottom", "right", "left")) + .If($"{prefixCls}-rtl", () => RTL) ; this.TitleClassMapper.Clear() diff --git a/components/drawer/DrawerContainer.razor b/components/drawer/DrawerContainer.razor index 66b1a60147..8a55260d75 100644 --- a/components/drawer/DrawerContainer.razor +++ b/components/drawer/DrawerContainer.razor @@ -1,7 +1,7 @@ @namespace AntDesign @inherits AntDomComponentBase -@foreach (IDrawerRef drawerRef in _drawerRefs) +@foreach (DrawerRef drawerRef in _drawerRefs) { var drawerConfig = drawerRef.Options; _drawerRefs = new List(); + private readonly List _drawerRefs = new List(); /// /// Create and Open a drawer /// - private async Task DrawerService_OnCreate(IDrawerRef drawerRef) + private async Task DrawerService_OnCreate(DrawerRef drawerRef) { - drawerRef.Options.Visible = true; + drawerRef.Config.Visible = true; if (!_drawerRefs.Contains(drawerRef)) { _drawerRefs.Add(drawerRef); @@ -39,12 +42,25 @@ private async Task DrawerService_OnCreate(IDrawerRef drawerRef) await InvokeAsync(StateHasChanged); } + /// + /// Update drawer + /// + /// + /// + private async Task DrawerService_OnUpdateEvent(DrawerRef drawerRef) + { + if (_drawerRefs.Contains(drawerRef)) + { + await InvokeStateHasChangedAsync(); + } + } + /// /// Close the drawer /// - private async Task DrawerService_OnClose(IDrawerRef drawerRef) + private async Task DrawerService_OnClose(DrawerRef drawerRef) { - drawerRef.Options.Visible = false; + drawerRef.Config.Visible = false; await InvokeAsync(StateHasChanged); await Task.Delay(300); if (_drawerRefs.Contains(drawerRef)) diff --git a/components/drawer/DrawerRef.cs b/components/drawer/DrawerRef.cs index 270dfbc131..90f849ad53 100644 --- a/components/drawer/DrawerRef.cs +++ b/components/drawer/DrawerRef.cs @@ -1,40 +1,53 @@ using System; using System.Collections.Generic; +using System.ComponentModel; using System.Text; using System.Threading.Tasks; namespace AntDesign { - public class DrawerRef : IDrawerRef + public class DrawerRef : FeedbackRefBase { - public DrawerOptions Options { get; set; } + [EditorBrowsable(EditorBrowsableState.Never)] + [Obsolete("Please replace it with Config")] + public DrawerOptions Options => Config; - public Drawer Drawer { get; set; } - - public Func OnOpen { get; set; } + public DrawerOptions Config { get; private set; } - public Func OnClosing { get; set; } + public Drawer Drawer { get; set; } - public Func OnClosed { get; set; } + public Func OnClosing { get; set; } - private DrawerService _service; + protected readonly DrawerService _service; - internal DrawerRef(DrawerOptions options) + internal DrawerRef(DrawerOptions options, DrawerService service) { - Options = options; + Config = options; + _service = service; } - internal DrawerRef(DrawerOptions options, DrawerService service) + /// + /// close Confirm dialog + /// + /// + public override async Task CloseAsync() { - Options = options; - _service = service; + var e = new ModalClosingEventArgs(); + await (OnClosing?.Invoke(e) ?? Task.CompletedTask); + if (!e.Cancel) + { + await _service.CloseAsync(this); + if (OnClose != null)//before close + await OnClose.Invoke(); + } } + /// - /// open a drawer + /// Open Confirm dialog /// /// - public async Task OpenAsync() + public override async Task OpenAsync() { await _service.OpenAsync(this); if (OnOpen != null) @@ -42,12 +55,34 @@ public async Task OpenAsync() } /// - /// close the drawer without return value + /// update Confirm dialog config which Visible=true /// /// - public async Task CloseAsync() + public override async Task UpdateConfigAsync() + { + await (_service?.UpdateAsync(this) ?? Task.CompletedTask); + } + + /// + /// update Confirm dialog config with a new ConfirmOptions + /// + /// + /// + public async Task UpdateConfigAsync(DrawerOptions config) + { + Config = config; + await UpdateConfigAsync(); + } + } + + public class DrawerRef : DrawerRef + { + internal TaskCompletionSource TaskCompletionSource { get; set; } + + public Func OnClosed { get; set; } + + internal DrawerRef(DrawerOptions options, DrawerService service) :base(options,service) { - await CloseAsync(default); } /// @@ -56,12 +91,12 @@ public async Task CloseAsync() /// public async Task CloseAsync(TResult result) { - var closeEventArgs = new DrawerClosingEventArgs(); + var closeEventArgs = new ModalClosingEventArgs(); if (OnClosing != null)//before close await OnClosing.Invoke(closeEventArgs); - if (closeEventArgs.Rejected) + if (closeEventArgs.Cancel) return; await _service.CloseAsync(this); @@ -69,10 +104,7 @@ public async Task CloseAsync(TResult result) if (OnClosed != null)//after close await OnClosed.Invoke(result); - if (TaskCompletionSource != null)//dialog close - TaskCompletionSource.SetResult(result); + TaskCompletionSource?.SetResult(result); } - - internal TaskCompletionSource TaskCompletionSource { get; set; } } } diff --git a/components/drawer/DrawerService.cs b/components/drawer/DrawerService.cs index 830837523e..145c8dc7cf 100644 --- a/components/drawer/DrawerService.cs +++ b/components/drawer/DrawerService.cs @@ -9,19 +9,22 @@ namespace AntDesign { public class DrawerService { - internal event Func OnOpenEvent; + internal event Func OnOpenEvent; + + internal event Func OnCloseEvent; + + internal event Func OnUpdateEvent; - internal event Func OnCloseEvent; /// /// Create and open a simple drawer without result /// /// drawer options /// The reference of drawer - public async Task CreateAsync(DrawerOptions options) + public async Task CreateAsync(DrawerOptions options) { CheckIsNull(options); - IDrawerRef drawerRef = new DrawerRef(options, this); + var drawerRef = new DrawerRef(options, this); await (OnOpenEvent?.Invoke(drawerRef) ?? Task.CompletedTask); return drawerRef; } @@ -35,7 +38,7 @@ public async Task CreateAsync(DrawerOptions options) /// /// /// The reference of drawer - public async Task> CreateAsync(DrawerOptions config, TComponentOptions options) where TComponent : DrawerTemplate + public async Task> CreateAsync(DrawerOptions config, TComponentOptions options) where TComponent : FeedbackComponent { CheckIsNull(config); @@ -45,7 +48,7 @@ public async Task CreateAsync(DrawerOptions options) RenderFragment child = (builder) => { builder.OpenComponent(0); - builder.AddAttribute(1, "DrawerRef", drawerRef); + builder.AddAttribute(1, "FeedbackRef", drawerRef); builder.AddAttribute(2, "Options", options); builder.CloseComponent(); }; @@ -54,7 +57,26 @@ public async Task CreateAsync(DrawerOptions options) return drawerRef; } - public async Task CreateDialogAsync(DrawerOptions config, TComponentOptions options) where TComponent : DrawerTemplate + /// + /// Update a drawer + /// + /// + /// + public async Task UpdateAsync(DrawerRef drawerRef) + { + await (OnUpdateEvent?.Invoke(drawerRef) ?? Task.CompletedTask); + } + + /// + /// Create and open a drawer + /// + /// + /// + /// + /// + /// + /// + public async Task CreateDialogAsync(DrawerOptions config, TComponentOptions options) where TComponent : FeedbackComponent { CheckIsNull(config); DrawerRef drawerRef = new DrawerRef(config, this); @@ -65,7 +87,7 @@ public async Task CreateAsync(DrawerOptions options) RenderFragment child = (builder) => { builder.OpenComponent(0); - builder.AddAttribute(1, "DrawerRef", drawerRef); + builder.AddAttribute(1, "FeedbackRef", drawerRef); builder.AddAttribute(2, "Options", options); builder.CloseComponent(); }; @@ -82,7 +104,7 @@ public async Task CreateAsync(DrawerOptions options) int width = 256, bool mask = true, bool noAnimation = false, - string placement = "right") where TComponent : DrawerTemplate + string placement = "right") where TComponent : FeedbackComponent { var config = new DrawerOptions() { @@ -97,7 +119,7 @@ public async Task CreateAsync(DrawerOptions options) return await CreateDialogAsync(config, options); } - internal Task OpenAsync(IDrawerRef drawerRef) + internal Task OpenAsync(DrawerRef drawerRef) { if (OnOpenEvent != null) { @@ -106,7 +128,7 @@ internal Task OpenAsync(IDrawerRef drawerRef) return Task.CompletedTask; } - internal Task CloseAsync(IDrawerRef drawerRef) + internal Task CloseAsync(DrawerRef drawerRef) { if (OnCloseEvent != null) { diff --git a/components/drawer/DrawerTemplate.razor.cs b/components/drawer/DrawerTemplate.razor.cs deleted file mode 100644 index 3437cc491c..0000000000 --- a/components/drawer/DrawerTemplate.razor.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Components; - -namespace AntDesign -{ - public class DrawerTemplate : TemplateComponentBase - { - [Parameter] - public DrawerRef DrawerRef { get; set; } - - /// - /// Close the drawer - /// - /// - protected async Task CloseAsync(TResult result = default) - { - await DrawerRef.CloseAsync(result); - } - - protected override void OnInitialized() - { - base.OnInitialized(); - DrawerRef.OnOpen?.Invoke(); - } - } -} diff --git a/components/drawer/IDrawerRef.cs b/components/drawer/IDrawerRef.cs deleted file mode 100644 index 65b9d6e81d..0000000000 --- a/components/drawer/IDrawerRef.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; -using System.Threading.Tasks; - -namespace AntDesign -{ - public interface IDrawerRef - { - DrawerOptions Options { get; set; } - - Drawer Drawer { get; set; } - - Task CloseAsync(); - - Func OnClosing { get; set; } - } -} diff --git a/components/empty/Empty.razor.cs b/components/empty/Empty.razor.cs index bfc4807884..2c07303d24 100644 --- a/components/empty/Empty.razor.cs +++ b/components/empty/Empty.razor.cs @@ -8,12 +8,6 @@ public partial class Empty : AntDomComponentBase [Parameter] public string PrefixCls { get; set; } = "ant-empty"; - /// - /// "ltr"|"rtl" - /// - [Parameter] - public string Direction { get; set; } = "ltr"; - [Parameter] public string ImageStyle { get; set; } @@ -43,8 +37,8 @@ protected void SetClass() this.ClassMapper.Clear() .Add(PrefixCls) .If($"{PrefixCls}-normal", () => Simple) - .GetIf(() => $"{PrefixCls}-{Direction}", () => Direction.IsIn("ltr", "rlt")) .If($"{PrefixCls}-small", () => Small) + .If($"{PrefixCls}-rtl", () => RTL) ; } diff --git a/components/form/ColLayoutParam.cs b/components/form/ColLayoutParam.cs index 42a64a0e57..3f0f09ed04 100644 --- a/components/form/ColLayoutParam.cs +++ b/components/form/ColLayoutParam.cs @@ -35,18 +35,18 @@ public class ColLayoutParam { Dictionary attributes = new Dictionary(); - attributes.Add("Flex", Flex); - attributes.Add("Span", Span); - attributes.Add("Order", Order); - attributes.Add("Offset", Offset); - attributes.Add("Push", Push); - attributes.Add("Pull", Pull); - attributes.Add("Xs", Xs); - attributes.Add("Sm", Sm); - attributes.Add("Md", Md); - attributes.Add("Lg", Lg); - attributes.Add("Xl", Xl); - attributes.Add("Xxl", Xxl); + attributes.Add(nameof(Col.Flex), Flex); + attributes.Add(nameof(Col.Span), Span); + attributes.Add(nameof(Col.Order), Order); + attributes.Add(nameof(Col.Offset), Offset); + attributes.Add(nameof(Col.Push), Push); + attributes.Add(nameof(Col.Pull), Pull); + attributes.Add(nameof(Col.Xs), Xs); + attributes.Add(nameof(Col.Sm), Sm); + attributes.Add(nameof(Col.Md), Md); + attributes.Add(nameof(Col.Lg), Lg); + attributes.Add(nameof(Col.Xl), Xl); + attributes.Add(nameof(Col.Xxl), Xxl); return attributes; } diff --git a/components/form/Form.razor.cs b/components/form/Form.razor.cs index 51c3c252b5..fa1587875d 100644 --- a/components/form/Form.razor.cs +++ b/components/form/Form.razor.cs @@ -22,6 +22,9 @@ public partial class Form : AntDomComponentBase, IForm [Parameter] public ColLayoutParam LabelCol { get; set; } = new ColLayoutParam(); + [Parameter] + public AntLabelAlignType? LabelAlign { get; set; } + [Parameter] public OneOf LabelColSpan { @@ -113,6 +116,7 @@ public TModel Model EditContext IForm.EditContext => _editContext; + AntLabelAlignType? IForm.LabelAlign => LabelAlign; string IForm.Size => Size; string IForm.Name => Name; object IForm.Model => Model; @@ -145,7 +149,8 @@ protected void SetClass() { this.ClassMapper.Clear() .Add(_prefixCls) - .Add($"{_prefixCls}-{Layout.ToLower()}") + .Get(() => $"{_prefixCls}-{Layout.ToLowerInvariant()}") + .If($"{_prefixCls}-rtl", () => RTL) ; } diff --git a/components/form/FormItem.razor b/components/form/FormItem.razor index a12a2d9dc1..03f17eb6f6 100644 --- a/components/form/FormItem.razor +++ b/components/form/FormItem.razor @@ -5,7 +5,7 @@ @if (!string.IsNullOrEmpty(Label) || LabelTemplate != null) { - + @if (LabelTemplate != null) { @LabelTemplate @@ -16,7 +16,7 @@ } } - +
diff --git a/components/form/FormItem.razor.cs b/components/form/FormItem.razor.cs index 0c96afae0e..301c66800e 100644 --- a/components/form/FormItem.razor.cs +++ b/components/form/FormItem.razor.cs @@ -37,6 +37,9 @@ public partial class FormItem : AntDomComponentBase, IFormItem [Parameter] public ColLayoutParam LabelCol { get; set; } + [Parameter] + public AntLabelAlignType? LabelAlign { get; set; } + [Parameter] public OneOf LabelColSpan { @@ -102,6 +105,9 @@ public partial class FormItem : AntDomComponentBase, IFormItem private PropertyReflector _propertyReflector; + private ClassMapper _labelClassMapper = new ClassMapper(); + private AntLabelAlignType? FormLabelAlign => LabelAlign ?? Form.LabelAlign; + protected override void OnInitialized() { base.OnInitialized(); @@ -111,22 +117,23 @@ protected override void OnInitialized() throw new InvalidOperationException("Form is null.FormItem should be childContent of Form."); } - Form.AddFormItem(this); - } - - protected override void OnParametersSet() - { - base.OnParametersSet(); - SetClass(); + + Form.AddFormItem(this); } protected void SetClass() { - this.ClassMapper.Clear() + this.ClassMapper .Add(_prefixCls) .If($"{_prefixCls}-with-help {_prefixCls}-has-error", () => _isValid == false) + .If($"{_prefixCls}-rtl", () => RTL) ; + + _labelClassMapper + .Add($"{_prefixCls}-label") + .If($"{_prefixCls}-label-left", () => FormLabelAlign == AntLabelAlignType.Left) + ; } private Dictionary GetLabelColAttributes() diff --git a/components/form/Internal/IForm.cs b/components/form/Internal/IForm.cs index 07e70a82da..bb3f16f333 100644 --- a/components/form/Internal/IForm.cs +++ b/components/form/Internal/IForm.cs @@ -10,6 +10,8 @@ public interface IForm internal ColLayoutParam LabelCol { get; } + internal AntLabelAlignType? LabelAlign { get; } + internal EditContext EditContext { get; } internal string Size { get; } diff --git a/components/form/style/index.less b/components/form/style/index.less index 718821f43f..5ea9f43c2f 100644 --- a/components/form/style/index.less +++ b/components/form/style/index.less @@ -130,6 +130,7 @@ // Optional mark .@{form-item-prefix-cls}-tooltip { color: @text-color-secondary; + cursor: help; writing-mode: horizontal-tb; margin-inline-start: @margin-xss; } diff --git a/components/grid/Col.razor.cs b/components/grid/Col.razor.cs index 3c7441ae28..4bd80212cb 100644 --- a/components/grid/Col.razor.cs +++ b/components/grid/Col.razor.cs @@ -81,11 +81,12 @@ private void SetHostClassMap() var prefixCls = "ant-col"; this.ClassMapper.Clear() .Add(prefixCls) - .GetIf(()=>$"{prefixCls}-{this.Span.Value}", () => this.Span.Value != null) + .GetIf(() => $"{prefixCls}-{this.Span.Value}", () => this.Span.Value != null) .GetIf(() => $"{prefixCls}-order-{this.Order.Value}", () => this.Order.Value != null) .GetIf(() => $"{prefixCls}-offset-{this.Offset.Value}", () => this.Offset.Value != null) .GetIf(() => $"{prefixCls}-pull-{this.Pull.Value}", () => this.Pull.Value != null) .GetIf(() => $"{prefixCls}-push-{this.Push.Value}", () => this.Push.Value != null) + .If($"{prefixCls}-rtl", () => RTL) ; SetSizeClassMapper(prefixCls, Xs, "xs"); @@ -146,4 +147,4 @@ protected override void Dispose(bool disposing) base.Dispose(disposing); } } -} +} \ No newline at end of file diff --git a/components/grid/Row.razor.cs b/components/grid/Row.razor.cs index 63001adea5..74029a5656 100644 --- a/components/grid/Row.razor.cs +++ b/components/grid/Row.razor.cs @@ -83,6 +83,7 @@ protected override async Task OnInitializedAsync() .If($"{prefixCls}-space-around", () => Justify == "space-around") .If($"{prefixCls}-space-between", () => Justify == "space-between") .If($"{prefixCls}-no-wrap", () => !Wrap) + .If($"{prefixCls}-rtl", () => RTL) ; if (DefaultBreakpoint != null) @@ -179,4 +180,4 @@ public enum BreakpointEnum sm, xs } -} +} \ No newline at end of file diff --git a/components/gulpfile.js b/components/gulpfile.js index 04d9cc1f62..f925306912 100644 --- a/components/gulpfile.js +++ b/components/gulpfile.js @@ -9,7 +9,7 @@ var uglify = require('gulp-uglify'); var sourcemaps = require('gulp-sourcemaps'); var buffer = require('vinyl-buffer'); -gulp.task('less', function () { +gulp.task('less-default', function () { return gulp .src('ant-design-blazor.less') .pipe(less({ javascriptEnabled: true })) @@ -17,6 +17,30 @@ gulp.task('less', function () { .pipe(gulp.dest('wwwroot/css')); }); +gulp.task('less-aliyun', function () { + return gulp + .src('ant-design-blazor.aliyun.less') + .pipe(less({ javascriptEnabled: true })) + .pipe(cleanCss({ compatibility: 'ie8' })) + .pipe(gulp.dest('wwwroot/css')); +}); + +gulp.task('less-compact', function () { + return gulp + .src('ant-design-blazor.compact.less') + .pipe(less({ javascriptEnabled: true })) + .pipe(cleanCss({ compatibility: 'ie8' })) + .pipe(gulp.dest('wwwroot/css')); +}); + +gulp.task('less-dark', function () { + return gulp + .src('ant-design-blazor.dark.less') + .pipe(less({ javascriptEnabled: true })) + .pipe(cleanCss({ compatibility: 'ie8' })) + .pipe(gulp.dest('wwwroot/css')); +}); + gulp.task('ts', function () { return browserify({ basedir: '.', @@ -43,4 +67,4 @@ gulp.task('src', function () { return gulp.src(['**/*.less', '!wwwroot/**']).pipe(gulp.dest('wwwroot/less')); }); -gulp.task('default', gulp.parallel('less', 'ts', 'src'), function () { }); \ No newline at end of file +gulp.task('default', gulp.parallel('less-default', 'less-aliyun', 'less-compact', 'less-dark', 'ts', 'src'), function () { }); \ No newline at end of file diff --git a/components/input-number/InputNumber.razor b/components/input-number/InputNumber.razor index eb177b7b1a..f8344dc0fb 100644 --- a/components/input-number/InputNumber.razor +++ b/components/input-number/InputNumber.razor @@ -4,15 +4,15 @@
- + - +
+ aria-valuenow="@CurrentValue" class="ant-input-number-input" @bind="@CurrentValueAsString" @oninput="OnInput" @onkeydown="OnKeyDown" @onfocus="@OnFocus" @onblur="@OnBlurAsync" disabled="@Disabled" />
diff --git a/components/input-number/InputNumber.razor.cs b/components/input-number/InputNumber.razor.cs index 3ee3e94bd9..07fcc11b0e 100644 --- a/components/input-number/InputNumber.razor.cs +++ b/components/input-number/InputNumber.razor.cs @@ -4,8 +4,10 @@ using System.Linq; using System.Linq.Expressions; using System.Text.RegularExpressions; +using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Components; +using Microsoft.AspNetCore.Components.Web; namespace AntDesign { @@ -144,6 +146,10 @@ public TValue Step private string _inputString; private bool _focused; + private readonly int _interval = 200; + private CancellationTokenSource _increaseTokenSource; + private CancellationTokenSource _decreaseTokenSource; + public InputNumber() { _isNullable = _surfaceType.IsGenericType && _surfaceType.GetGenericTypeDefinition() == typeof(Nullable<>); @@ -220,6 +226,7 @@ protected override void OnInitialized() SetClass(); CurrentValue = Value ?? DefaultValue; } + /// /// Always return true, if input string is invalid, result = default, if input string is null or empty, result = DefaultValue /// @@ -272,10 +279,13 @@ private void SetClass() .If($"{PrefixCls}-lg", () => Size == InputSize.Large) .If($"{PrefixCls}-sm", () => Size == InputSize.Small) .If($"{PrefixCls}-focused", () => _focused) - .If($"{PrefixCls}-disabled", () => this.Disabled); + .If($"{PrefixCls}-disabled", () => this.Disabled) + .If($"{PrefixCls}-rtl", () => RTL); } - private async Task Increase() + #region Value Increase and Decrease Methods + + private async Task IncreaseDown() { if (_isNullable && Value == null) { @@ -288,9 +298,30 @@ private async Task Increase() await SetFocus(); var num = _increaseFunc(Value, _step); await ChangeValueAsync(num); + + _increaseTokenSource = new CancellationTokenSource(); + _ = Increase(_increaseTokenSource.Token).ConfigureAwait(false); } - private async Task Decrease() + private void IncreaseUp() => _increaseTokenSource?.Cancel(); + + private async Task Increase(CancellationToken cancellationToken) + { + await Task.Delay(600, CancellationToken.None); + while (true) + { + if (_equalToFunc(Value, Max) || cancellationToken.IsCancellationRequested) + { + return; + } + var num = _increaseFunc(Value, _step); + await ChangeValueAsync(num); + StateHasChanged(); + await Task.Delay(_interval, CancellationToken.None); + } + } + + private async Task DecreaseDown() { if (_isNullable && Value == null) { @@ -303,8 +334,59 @@ private async Task Decrease() await SetFocus(); var num = _decreaseFunc(Value, _step); await ChangeValueAsync(num); + + _decreaseTokenSource = new CancellationTokenSource(); + _ = Decrease(_decreaseTokenSource.Token).ConfigureAwait(false); } + private void DecreaseUp() => _decreaseTokenSource?.Cancel(); + + private async Task Decrease(CancellationToken cancellationToken) + { + await Task.Delay(600, CancellationToken.None); + while (true) + { + if (_equalToFunc(Value, Min) || cancellationToken.IsCancellationRequested) + { + return; + } + var num = _decreaseFunc(Value, _step); + await ChangeValueAsync(num); + StateHasChanged(); + await Task.Delay(_interval, CancellationToken.None); + } + } + + private async Task OnKeyDown(KeyboardEventArgs e) + { + if (_isNullable && Value == null) + { + return; + } + if (e.Key == "ArrowUp") + { + if (_equalToFunc(Value, Max)) + { + return; + } + var num = _increaseFunc(Value, _step); + await ChangeValueAsync(num); + StateHasChanged(); + } + else if (e.Key == "ArrowDown") + { + if (_equalToFunc(Value, Min)) + { + return; + } + var num = _decreaseFunc(Value, _step); + await ChangeValueAsync(num); + StateHasChanged(); + } + } + + #endregion Value Increase and Decrease Methods + private async Task SetFocus() { _focused = true; diff --git a/components/input/Input.cs b/components/input/Input.cs index 33b15692f6..b3e916ba09 100644 --- a/components/input/Input.cs +++ b/components/input/Input.cs @@ -144,7 +144,9 @@ protected virtual void SetClasses() ClassMapper.Clear() .Add($"{PrefixCls}") .If($"{PrefixCls}-lg", () => Size == InputSize.Large) - .If($"{PrefixCls}-sm", () => Size == InputSize.Small); + .If($"{PrefixCls}-sm", () => Size == InputSize.Small) + .If($"{PrefixCls}-rtl", () => RTL) + ; Attributes ??= new Dictionary(); diff --git a/components/input/InputGroup.razor.cs b/components/input/InputGroup.razor.cs index 3f2d7a0f69..71da084aef 100644 --- a/components/input/InputGroup.razor.cs +++ b/components/input/InputGroup.razor.cs @@ -24,7 +24,8 @@ protected override void OnInitialized() .Add(PrefixCls) .If($"{PrefixCls}-lg", () => Size == InputSize.Large) .If($"{PrefixCls}-sm", () => Size == InputSize.Small) - .If($"{PrefixCls}-compact", () => Compact); + .If($"{PrefixCls}-compact", () => Compact) + .If($"{PrefixCls}-rtl", () => RTL); } } } diff --git a/components/input/InputPassword.razor.cs b/components/input/InputPassword.razor.cs index afd89e39cb..e88673c330 100644 --- a/components/input/InputPassword.razor.cs +++ b/components/input/InputPassword.razor.cs @@ -25,7 +25,8 @@ protected override void SetClasses() //ant-input-password-large ant-input-affix-wrapper ant-input-affix-wrapper-lg ClassMapper .If($"{PrefixCls}-password-large", () => Size == InputSize.Large) - .If($"{PrefixCls}-password-small", () => Size == InputSize.Small); + .If($"{PrefixCls}-password-small", () => Size == InputSize.Small) + .If($"{PrefixCls}-password-rtl", () => RTL); AffixWrapperClass = string.Join(" ", AffixWrapperClass, $"{PrefixCls}-password"); diff --git a/components/input/TextArea.razor b/components/input/TextArea.razor index 116c673d65..8b695c3a06 100644 --- a/components/input/TextArea.razor +++ b/components/input/TextArea.razor @@ -19,7 +19,7 @@ { "style", Style }, { "class", ClassMapper.Class }, { "disabled", Disabled }, - }; + }; if (Attributes != null) { @@ -29,7 +29,7 @@ @if (Suffix != null) { - +