diff --git a/src/MudBlazor.Docs.Compiler/ApiDocumentationBuilder.cs b/src/MudBlazor.Docs.Compiler/ApiDocumentationBuilder.cs index 0d1a2ec1cc82..7d23297b9252 100644 --- a/src/MudBlazor.Docs.Compiler/ApiDocumentationBuilder.cs +++ b/src/MudBlazor.Docs.Compiler/ApiDocumentationBuilder.cs @@ -2,14 +2,9 @@ // MudBlazor 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; -using System.IO; -using System.Linq; using System.Reflection; using System.Text.RegularExpressions; -using System.Xml; +using LoxSmoke.DocXml; using Microsoft.AspNetCore.Components; namespace MudBlazor.Docs.Compiler; @@ -30,7 +25,12 @@ public partial class ApiDocumentationBuilder() /// /// The assembly to document. /// - public Assembly Assembly { get; private set; } = typeof(_Imports).Assembly; + public List Assemblies { get; private set; } = [typeof(_Imports).Assembly]; + + /// + /// The reader for XML documentation. + /// + private DocXmlReader _xmlDocs; /// /// The types in the assembly. @@ -62,89 +62,33 @@ public partial class ApiDocumentationBuilder() /// public SortedDictionary Methods { get; private set; } = []; - /// - /// The types which have documentation but could not be linked to a reflected type. - /// - /// - /// When items exist in this list, the code may need to be improved to find the reflected type. - /// - public List UnresolvedTypes { get; private set; } = []; - - /// - /// The properties which have documentation but could not be linked to a reflected property. - /// - /// - /// When items exist in this list, the code may need to be improved to find the reflected property. - /// - public List UnresolvedProperties { get; private set; } = []; - - /// - /// The types which have documentation but could not be linked to a reflected field. - /// - /// - /// When items exist in this list, the code may need to be improved to find the reflected field. - /// - public List UnresolvedFields { get; private set; } = []; - - /// - /// The types which have documentation but could not be linked to a reflected method. - /// - /// - /// When items exist in this list, the code may need to be improved to find the reflected method. - /// - public List UnresolvedMethods { get; private set; } = []; - - /// - /// The types which have documentation but could not be linked to a reflected event. - /// - /// - /// When items exist in this list, the code may need to be improved to find the reflected event. - /// - public List UnresolvedEvents { get; private set; } = []; - /// /// Any types to exclude from documentation. /// public static List ExcludedTypes { get; private set; } = [ + "ActivatableCallback", + "AbstractLocalizationInterceptor", + "CloneableCloneStrategy`1", + "CssBuilder", "MudBlazor._Imports", + "MudBlazor.CategoryAttribute", "MudBlazor.CategoryTypes", "MudBlazor.CategoryTypes+", "MudBlazor.Colors", "MudBlazor.Colors+", - "MudBlazor.Resources.LanguageResource", "MudBlazor.Icons", "MudBlazor.Icons+", + "MudBlazor.LabelAttribute", + "MudBlazor.Resources.LanguageResource", + "object", "string" ]; - /// - /// Gets whether a type is excluded from documentation. - /// - /// The type to check. - /// When true, the type is excluded from documentation. - public static bool IsExcluded(Type type) - { - if (ExcludedTypes.Contains(type.Name)) - { - return true; - } - if (type.FullName != null && ExcludedTypes.Contains(type.FullName)) - { - return true; - } - if (type.FullName != null && ExcludedTypes.Any(excludedType => type.FullName.StartsWith(excludedType))) - { - return true; - } - - return false; - } - /// /// Any methods to exclude from documentation. /// - public static List ExcludedMethods { get; private set; } = + public static List ExcludedMembers { get; private set; } = [ // Object methods "ToString", @@ -175,26 +119,62 @@ public static bool IsExcluded(Type type) "OnParametersSetAsync", "StateHasChanged", "ShouldRender", + "DispatchExceptionAsync", + "SetParametersAsync", + "CreateRegisterScope", // Dispose methods "Dispose", "DisposeAsync", "Finalize", - // Internal MudBlazor methods - "SetParametersAsync", - "DispatchExceptionAsync", - "CreateRegisterScope", - "DetectIllegalRazorParametersV7", - "MudBlazor.Interfaces.IMudStateHasChanged.StateHasChanged", ]; + /// + /// Gets whether a type is excluded from documentation. + /// + /// The type to check. + /// When true, the type is excluded from documentation. + public static bool IsExcluded(Type type) + { + if (ExcludedTypes.Contains(type.Name)) + { + return true; + } + if (type.FullName != null && ExcludedTypes.Contains(type.FullName)) + { + return true; + } + if (type.FullName != null && ExcludedTypes.Any(excludedType => type.FullName.StartsWith(excludedType))) + { + return true; + } + + return false; + } + + /// + /// Gets whether a type is excluded from documentation. + /// + /// The type to check. + /// When true, the type is excluded from documentation. + public static bool IsExcluded(MemberInfo member) + { + if (ExcludedMembers.Contains(member.Name)) + { + return true; + } + + return false; + } + /// /// Generates documentation for all types. /// public bool Execute() { + _xmlDocs = new(Assemblies); AddTypesToDocument(); + FindDeclaringTypes(); AddGlobalsToDocument(); - MergeXmlDocumentation(); ExportApiDocumentation(); CalculateDocumentationCoverage(); return true; @@ -205,11 +185,33 @@ public bool Execute() /// public void AddTypesToDocument() { - // Get all MudBlazor public types - PublicTypes = new(Assembly.GetTypes().Where(type => type.IsPublic).ToDictionary(r => r.Name, v => v)); - foreach (var type in PublicTypes) + foreach (var assembly in Assemblies) + { + // Document all public types + var typesToDocument = assembly.GetTypes() + .Where(type => + // Include public types + type.IsPublic + // ... which aren't internal + + // ... which aren't excluded + && !IsExcluded(type) + // ... which aren't interfaces + && !type.IsInterface + // ... which aren't source generators + && !type.Name.Contains("SourceGenerator") + // ... which aren't extension classes + && !type.Name.Contains("Extensions")) + .ToList(); + foreach (var type in typesToDocument) + { + PublicTypes.Add(type.Name, type); + } + } + // Now build all public members + foreach (var pair in PublicTypes) { - AddTypeToDocument(type.Value); + AddTypeToDocument(pair.Value); } } @@ -219,24 +221,22 @@ public void AddTypesToDocument() /// The type to add. public DocumentedType AddTypeToDocument(Type type) { - // Is this type excluded? - if (IsExcluded(type)) - { - return null; - } - // Is the type already documented? if (!Types.TryGetValue(type.FullName, out var documentedType)) { - // No. + // Look up the XML documentation + var typeXmlDocs = _xmlDocs.GetTypeComments(type); + + // No. Add it documentedType = new DocumentedType() { BaseType = type.BaseType, IsPublic = type.IsPublic, IsAbstract = type.IsNestedFamORAssem, Key = type.FullName, - XmlKey = GetXmlKey(type.FullName), Name = type.Name, + Remarks = typeXmlDocs.Remarks?.Replace("\r\n", "").Trim(), + Summary = typeXmlDocs.Summary?.Replace("\r\n", "").Trim(), Type = type, }; @@ -249,6 +249,9 @@ public DocumentedType AddTypeToDocument(Type type) AddFieldsToDocument(type, documentedType); AddEventsToDocument(type, documentedType); + // Look for binable properties + FindBindableProperties(documentedType); + // Also add nested types foreach (var nestedType in type.GetNestedTypes(BindingFlags.Public)) { @@ -259,92 +262,6 @@ public DocumentedType AddTypeToDocument(Type type) return documentedType; } - /// - /// Gets the XML member key for the specified type and member. - /// - /// The of the type containing the member. - /// The fully qualified name of the member. - /// The member key for looking up documentation. - public static string GetXmlKey(string typeFullName, string memberName = null) - { - // See: https://learn.microsoft.com/archive/msdn-magazine/2019/october/csharp-accessing-xml-documentation-via-reflection - - // Get the key for the type - var key = TypeFullNameRegEx().Replace(typeFullName, string.Empty).Replace('+', '.'); - return (memberName != null) ? key + "." + memberName : key; - } - - /// - /// Gets the XML member key for the specified type and method. - /// - /// The of the type containing the member. - /// The fully qualified name of the member. - /// The member key for looking up documentation. - public static string GetXmlKey(string typeFullNameString, MethodInfo methodInfo) - { - if (methodInfo.Name == "GetOrAdd") - { - Debugger.Break(); - } - - var typeGenericMap = new Dictionary(); - var tempTypeGeneric = 0; - Array.ForEach(methodInfo.DeclaringType.GetGenericArguments(), x => typeGenericMap[x.Name] = tempTypeGeneric++); - var methodGenericMap = new Dictionary(); - var tempMethodGeneric = 0; - Array.ForEach(methodInfo.GetGenericArguments(), x => methodGenericMap.Add(x.Name, tempMethodGeneric++)); - var parameterInfos = methodInfo.GetParameters().ToList(); - - var key = typeFullNameString + "." + methodInfo.Name; - - if (parameterInfos.Count > 0) - { - key += "("; - for (var index = 0; index < parameterInfos.Count; index++) - { - var parameterInfo = parameterInfos[index]; - if (index > 0) - { - key += ","; - } - key += parameterInfo.ParameterType.FullName; - - if (parameterInfo.ParameterType.HasElementType) - { - //Debugger.Break(); - // The type is either an array, pointer, or reference - if (parameterInfo.ParameterType.IsArray) - { - // Append the "[]" array brackets onto the element type - key += "[]"; - } - else if (parameterInfo.ParameterType.IsPointer) - { - // Append the "*" pointer symbol to the element type - } - else if (parameterInfo.ParameterType.IsByRef) - { - // Append the "@" symbol to the element type - } - } - else if (parameterInfo.ParameterType.IsGenericParameter) - { - // Look up the index of the generic from the - // dictionaries in Figure 5, appending "`" if - // the parameter is from a type or "``" if the - // parameter is from a method - //Debugger.Break(); - } - else - { - // Nothing fancy, just convert the type to a string - } - } - key += ")"; - } - return key; - } - /// /// Adds public properties for the specified type. /// @@ -355,6 +272,11 @@ public void AddPropertiesToDocument(Type type, DocumentedType documentedType) var properties = type.GetProperties().ToList(); // Add protected methods properties.AddRange(type.GetProperties(BindingFlags.Instance | BindingFlags.NonPublic)); + // Remove properties we don't want on the site + properties.RemoveAll(property => + property.GetMethod.IsPrivate // Remove private properties + || property.GetMethod.IsAssembly // Remove internal properties + || IsExcluded(property)); // Remove properties from the manually maintained list // Remove duplicates properties = properties.DistinctBy(property => property.Name).ToList(); // Go through each property @@ -364,27 +286,61 @@ public void AddPropertiesToDocument(Type type, DocumentedType documentedType) var blazorParameter = property.GetCustomAttribute(); var key = GetPropertyFullName(property); - // Has this property been documented before? - if (!Properties.TryGetValue(key, out var documentedProperty)) + // Is this an event? + if (property.PropertyType.Name.StartsWith("EventCallback")) { - // No. - documentedProperty = new DocumentedProperty() + // Has this event been documented before? + if (!Events.TryGetValue(key, out var documentedEvent)) { - Category = category?.Name, - DeclaringType = property.DeclaringType, - DeclaringTypeFullName = GetTypeFullName(property.DeclaringType), - IsProtected = property.GetMethod.IsFamily, - IsParameter = blazorParameter != null, - Key = key, - Name = property.Name, - Order = category?.Order, - Type = property.PropertyType, - XmlKey = GetXmlKey(GetTypeFullName(property.DeclaringType), property.Name), - }; - Properties.Add(key, documentedProperty); + // No. Get the XML documentation + var xmlDocs = _xmlDocs.GetMemberComments(property); + + // Record this event + documentedEvent = new DocumentedEvent() + { + Category = category?.Name, + DeclaringType = property.DeclaringType, + IsProtected = property.GetMethod.IsFamily, + IsParameter = blazorParameter != null, + Key = key, + Name = property.Name, + Order = category == null ? int.MaxValue : category.Order, + Remarks = xmlDocs.Remarks?.Replace("\r\n", "").Trim(), + Summary = xmlDocs.Summary?.Replace("\r\n", "").Trim(), + Type = property.PropertyType, + }; + Events.Add(key, documentedEvent); + } + // Link the event to the type + documentedType.Events.Add(documentedEvent.Key, documentedEvent); + } + else + { + // Has this property been documented before? + if (!Properties.TryGetValue(key, out var documentedProperty)) + { + // No. Get the XML documentation + var xmlDocs = _xmlDocs.GetMemberComments(property); + + // Record this property + documentedProperty = new DocumentedProperty() + { + Category = category?.Name, + DeclaringType = property.DeclaringType, + IsProtected = property.GetMethod.IsFamily, + IsParameter = blazorParameter != null, + Key = key, + Name = property.Name, + Order = category == null ? int.MaxValue : category.Order, + Remarks = xmlDocs.Remarks?.Replace("\r\n", "").Trim(), + Summary = xmlDocs.Summary?.Replace("\r\n", "").Trim(), + Type = property.PropertyType, + }; + Properties.Add(key, documentedProperty); + } + // Link the property to the type + documentedType.Properties.Add(documentedProperty.Key, documentedProperty); } - // Link the property to the type - documentedType.Properties.Add(documentedProperty.Key, documentedProperty); } } @@ -398,21 +354,29 @@ public void AddFieldsToDocument(Type type, DocumentedType documentedType) var fields = type.GetFields().ToList(); // Add protected methods fields.AddRange(type.GetFields(BindingFlags.Instance | BindingFlags.NonPublic)); - // Remove private and backing fields - fields.RemoveAll(field => field.Name.Contains("k__BackingField") || field.Name == "value__" || field.Name.StartsWith('_')); + // Remove fields we don't want documented + fields.RemoveAll(field => + field.Name.Contains("k__BackingField") // Remove backing fields + || field.Name == "value__" + || field.Name.StartsWith('_') + || field.IsPrivate // Remove private fields + || field.IsAssembly // Remove internal fields + || IsExcluded(field)); // Remove fields the team doesn't want shown // Remove duplicates fields = fields.DistinctBy(property => property.Name).ToList(); // Go through each property foreach (var field in fields) { var category = field.GetCustomAttribute(); - var blazorParameter = field.GetCustomAttribute(); var key = GetFieldFullName(field); // Has this property been documented before? if (!Fields.TryGetValue(key, out var documentedField)) { - // No. + // No. Get the XML documentation + var xmlDocs = _xmlDocs.GetMemberComments(field); + + // Record this property documentedField = new DocumentedField() { Category = category?.Name, @@ -420,9 +384,10 @@ public void AddFieldsToDocument(Type type, DocumentedType documentedType) IsProtected = field.IsFamily, Key = key, Name = field.Name, - Order = category?.Order, + Order = category == null ? int.MaxValue : category.Order, + Remarks = xmlDocs.Remarks?.Replace("\r\n", "").Trim(), + Summary = xmlDocs.Summary?.Replace("\r\n", "").Trim(), Type = field.FieldType, - XmlKey = GetXmlKey(GetTypeFullName(field.DeclaringType), field.Name), }; Fields.Add(key, documentedField); } @@ -441,6 +406,10 @@ public void AddEventsToDocument(Type type, DocumentedType documentedType) var events = type.GetEvents().ToList(); // Add protected methods events.AddRange(type.GetEvents(BindingFlags.Instance | BindingFlags.NonPublic)); + // Remove unwanted events + events.RemoveAll(eventItem => + eventItem.AddMethod.IsPrivate // Remove private events + || eventItem.AddMethod.IsAssembly); // Remove internal events // Remove duplicates events = events.DistinctBy(property => property.Name).ToList(); // Go through each property @@ -460,9 +429,8 @@ public void AddEventsToDocument(Type type, DocumentedType documentedType) DeclaringType = eventItem.DeclaringType, Key = key, Name = eventItem.Name, - Order = category?.Order, + Order = category == null ? int.MaxValue : category.Order, Type = eventItem.EventHandlerType, - XmlKey = GetXmlKey(GetTypeFullName(eventItem.DeclaringType), eventItem.Name), }; Events.Add(key, documentedEvent); } @@ -471,6 +439,61 @@ public void AddEventsToDocument(Type type, DocumentedType documentedType) } } + /// + /// Looks for properties with an associated "____Changed" event. + /// + /// The documented type to search. + public static void FindBindableProperties(DocumentedType type) + { + // Look for "[Property]Changed" event callbacks + var changedEvents = type.Events.Where(eventItem => eventItem.Value.Name.EndsWith("Changed", StringComparison.OrdinalIgnoreCase)); + foreach (var eventItem in changedEvents) + { + // Look for a property for this event callback + var property = type.Properties.SingleOrDefault(property => property.Value.Name.Equals(eventItem.Value.Name.Replace("Changed", "", StringComparison.OrdinalIgnoreCase))); + if (property.Value != null) + { + property.Value.ChangeEvent = eventItem.Value; + eventItem.Value.Property = property.Value; + } + } + } + + /// + /// Calculates the types in which all members are declared. + /// + public void FindDeclaringTypes() + { + foreach (var property in Properties) + { + if (Types.TryGetValue(GetTypeFullName(property.Value.DeclaringType), out var documentedType)) + { + property.Value.DeclaringDocumentedType = documentedType; + } + } + foreach (var field in Fields) + { + if (Types.TryGetValue(GetTypeFullName(field.Value.DeclaringType), out var documentedType)) + { + field.Value.DeclaringDocumentedType = documentedType; + } + } + foreach (var method in Methods) + { + if (Types.TryGetValue(GetTypeFullName(method.Value.DeclaringType), out var documentedType)) + { + method.Value.DeclaringDocumentedType = documentedType; + } + } + foreach (var eventItem in Events) + { + if (Types.TryGetValue(GetTypeFullName(eventItem.Value.DeclaringType), out var documentedType)) + { + eventItem.Value.DeclaringDocumentedType = documentedType; + } + } + } + /// /// Gets the full name of the property's declaring type. /// @@ -574,54 +597,53 @@ public void AddMethodsToDocument(Type type, DocumentedType documentedType) var methods = type.GetMethods().ToList(); // Add protected methods methods.AddRange(type.GetMethods(BindingFlags.Instance | BindingFlags.NonPublic)); - methods = methods - // Remove duplicates - .DistinctBy(method => method.Name) - .Where(method => - // Exclude getter and setter methods - !method.Name.StartsWith("get_") - && !method.Name.StartsWith("set_") - // Exclude inherited .NET methods - && !method.Name.StartsWith("Microsoft") - && !method.Name.StartsWith("System") - ) - .OrderBy(method => method.Name) - .ToList(); + // Remove methods we don't want on the site + methods.RemoveAll(method => method.IsPrivate // Remove private methods + || method.IsAssembly // Remove internal methods + || IsExcluded(method) // Remove some internal methods + || method.Name.StartsWith("add_") // Remove event subscribers + || method.Name.StartsWith("remove_") // Remove event unsubscribers + || method.Name.StartsWith("get_") // Remove property getters + || method.Name.StartsWith("set_") // Remove property setters + || method.Name.StartsWith("Microsoft") // Remove object methods + || method.Name.StartsWith("System")); // Remove built-in methods + // Remove duplicates + methods = methods.DistinctBy(method => method.Name).ToList(); // Look for methods and add related types foreach (var method in methods) { - //if (method.Name.Contains("ToDescriptionString")) - //{ - // Debugger.Break(); - //} - // Get the key for this method var key = GetMethodFullName(method); // Has this been documented before? if (!Methods.TryGetValue(key, out var documentedMethod)) { - // No. + // No. Get the XML documentation + var xmlDocs = _xmlDocs.GetMethodComments(method); + + // Record this property documentedMethod = new DocumentedMethod() { DeclaringType = method.DeclaringType, IsProtected = method.IsFamily, Key = key, Name = method.Name, + Returns = xmlDocs.Returns?.Replace("\r\n", "").Trim(), + Remarks = xmlDocs.Remarks?.Replace("\r\n", "").Trim(), + Summary = xmlDocs.Summary?.Replace("\r\n", "").Trim(), Type = method.ReturnType, - XmlKey = GetXmlKey(GetTypeFullName(method.DeclaringType), method) }; // Reach out and document types mentioned in these methods foreach (var parameter in method.GetParameters()) { + var (name, text) = xmlDocs.Parameters.SingleOrDefault(docParameter => docParameter.Name == parameter.Name); var documentedParameter = new DocumentedParameter() { Name = parameter.Name, Type = parameter.ParameterType, - TypeFullName = parameter.ParameterType.FullName, - TypeName = parameter.ParameterType.Name + Summary = text, }; - documentedMethod.Parameters.Add(parameter.Name, documentedParameter); + documentedMethod.Parameters.Add(documentedParameter); } // Add to the list Methods.Add(key, documentedMethod); @@ -631,127 +653,6 @@ public void AddMethodsToDocument(Type type, DocumentedType documentedType) } } - /// - /// Merges XML documentation with existing documentation types. - /// - /// - public void MergeXmlDocumentation() - { - // Open the XML documentation file - var path = Assembly.Location.Replace(".dll", ".xml", StringComparison.OrdinalIgnoreCase); - using var reader = new XmlTextReader(path); - reader.WhitespaceHandling = WhitespaceHandling.None; - reader.DtdProcessing = DtdProcessing.Ignore; - // Move to the first member - reader.ReadToFollowing("member"); - // Read each "" element - while (!reader.EOF) - { - var memberTypeAndName = reader.GetAttribute("name").Split(":"); - var content = reader.ReadInnerXml(); - switch (memberTypeAndName[0]) - { - case "T": // Type - DocumentType(memberTypeAndName[1], content); - break; - case "P": // Property - DocumentProperty(memberTypeAndName[1], content); - break; - case "M": // Method - DocumentMethod(memberTypeAndName[1], content); - break; - case "F": // Field (or Enum) - DocumentField(memberTypeAndName[1], content); - break; - case "E": // Event - DocumentEvent(memberTypeAndName[1], content); - break; - } - // Are we at the end of the document? - if (reader.NodeType == XmlNodeType.EndElement && reader.Name == "members") - { - break; - } - } - } - - /// - /// Adds HTML documentation for the specified type. - /// - /// The namespace and class of the member. - /// The raw XML documentation for the member. - public void DocumentType(string memberFullName, string xmlContent) - { - var type = Types.FirstOrDefault(type => type.Value.XmlKey == memberFullName); - if (type.Value != null) - { - type.Value.Remarks = GetRemarks(xmlContent); - type.Value.Summary = GetSummary(xmlContent); - } - else - { - UnresolvedTypes.Add(memberFullName); - } - } - - /// - /// Adds HTML documentation for the specified property. - /// - /// The namespace and class of the member. - /// The raw XML documentation for the member. - public void DocumentProperty(string memberFullName, string xmlContent) - { - var property = Properties.FirstOrDefault(type => type.Value.XmlKey == memberFullName); - if (property.Value != null) - { - property.Value.Summary = GetSummary(xmlContent); - property.Value.Remarks = GetRemarks(xmlContent); - } - else - { - UnresolvedProperties.Add(memberFullName); - } - } - - /// - /// Adds HTML documentation for the specified field. - /// - /// The namespace and class of the member. - /// The raw XML documentation for the member. - public void DocumentField(string memberFullName, string xmlContent) - { - var field = Fields.FirstOrDefault(type => type.Value.XmlKey == memberFullName); - if (field.Value != null) - { - field.Value.Summary = GetSummary(xmlContent); - field.Value.Remarks = GetRemarks(xmlContent); - } - else - { - UnresolvedFields.Add(memberFullName); - } - } - - /// - /// Adds HTML documentation for the specified field. - /// - /// The namespace and class of the member. - /// The raw XML documentation for the member. - public void DocumentMethod(string memberFullName, string xmlContent) - { - var method = Methods.FirstOrDefault(method => method.Value.XmlKey == memberFullName); - if (method.Value != null) - { - method.Value.Summary = GetSummary(xmlContent); - method.Value.Remarks = GetRemarks(xmlContent); - } - else - { - // No. It should be documented - UnresolvedMethods.Add(memberFullName); - } - } - /// /// Gets the name of a method without its parameters. /// @@ -781,46 +682,6 @@ public static string GetMethodName(string xmlMethodName) return xmlMethodName.Substring(xmlMethodName.LastIndexOf('.') + 1); } - /// - /// Adds HTML documentation for the specified field. - /// - /// The namespace and class of the member. - /// The raw XML documentation for the member. - public void DocumentEvent(string memberFullName, string xmlContent) - { - if (Events.TryGetValue(memberFullName, out var documentedType)) - { - documentedType.Summary = GetSummary(xmlContent); - documentedType.Remarks = GetRemarks(xmlContent); - } - else - { - UnresolvedEvents.Add(memberFullName); - } - } - - /// - /// Gets the content of the "summary" element as HTML. - /// - /// The member XML to search. - /// The HTML content of the member. - public static string GetSummary(string xml) - { - var summary = SummaryRegEx().Match(xml).Groups.GetValueOrDefault("1"); - return summary?.Value; - } - - /// - /// Gets the content of the "remarks" element as HTML. - /// - /// The member XML to search. - /// The HTML content of the member. - public static string GetRemarks(string xml) - { - var remarks = RemarksRegEx().Match(xml).Groups.GetValueOrDefault("1"); - return remarks?.Value; - } - /// /// Serializes all documentation to the MudBlazor.Docs "Generated" folder. /// @@ -836,6 +697,10 @@ public void ExportApiDocumentation() writer.WriteFields(Fields); writer.WriteEvents(Events); writer.WriteTypes(Types); + writer.LinkDocumentedTypes(Properties); + writer.LinkDocumentedTypes(Methods); + writer.LinkDocumentedTypes(Fields); + writer.LinkDocumentedTypes(Events); writer.WriteConstructorEnd(); writer.WriteClassEnd(); } @@ -846,47 +711,26 @@ public void ExportApiDocumentation() public void CalculateDocumentationCoverage() { // Calculate how many items have good documentation - var summarizedTypes = Types.Count(type => !string.IsNullOrEmpty(type.Value.Summary)); - var summarizedProperties = Properties.Count(property => !string.IsNullOrEmpty(property.Value.Summary)); - var summarizedMethods = Methods.Count(method => !string.IsNullOrEmpty(method.Value.Summary)); - var summarizedFields = Fields.Count(field => !string.IsNullOrEmpty(field.Value.Summary)); - var summarizedEvents = Events.Count(eventItem => !string.IsNullOrEmpty(eventItem.Value.Summary)); + var wellDocumentedTypes = Types.Count(type => !string.IsNullOrEmpty(type.Value.Summary)); + var wellDocumentedProperties = Properties.Count(property => !string.IsNullOrEmpty(property.Value.Summary)); + var wellDocumentedMethods = Methods.Count(method => !string.IsNullOrEmpty(method.Value.Summary)); + var wellDocumentedFields = Fields.Count(field => !string.IsNullOrEmpty(field.Value.Summary)); + var wellDocumentedEvents = Events.Count(eventItem => !string.IsNullOrEmpty(eventItem.Value.Summary)); // Calculate the coverage metrics for documentation - var typeCoverage = summarizedTypes / (double)Types.Count; - var propertyCoverage = summarizedProperties / (double)Properties.Count; - var methodCoverage = summarizedMethods / (double)Methods.Count; - var fieldCoverage = summarizedFields / (double)Fields.Count; - var eventCoverage = summarizedEvents / (double)Events.Count; + var typeCoverage = wellDocumentedTypes / (double)Types.Count; + var propertyCoverage = wellDocumentedProperties / (double)Properties.Count; + var methodCoverage = wellDocumentedMethods / (double)Methods.Count; + var fieldCoverage = wellDocumentedFields / (double)Fields.Count; + var eventCoverage = wellDocumentedEvents / (double)Events.Count; Console.WriteLine("XML Documentation Coverage for MudBlazor:"); Console.WriteLine(); - Console.WriteLine($"Types: {summarizedTypes} of {Types.Count} ({typeCoverage:P0}) other types"); - Console.WriteLine($"Properties: {summarizedProperties} of {Properties.Count} ({propertyCoverage:P0}) properties"); - Console.WriteLine($"Methods: {summarizedMethods} of {Methods.Count} ({methodCoverage:P0}) methods"); - Console.WriteLine($"Fields: {summarizedFields} of {Fields.Count} ({fieldCoverage:P0}) fields/enums"); - Console.WriteLine($"Events: {summarizedEvents} of {Events.Count} ({eventCoverage:P0}) events"); + Console.WriteLine($"Types: {wellDocumentedTypes} of {Types.Count} ({typeCoverage:P0}) types"); + Console.WriteLine($"Properties: {wellDocumentedProperties} of {Properties.Count} ({propertyCoverage:P0}) properties"); + Console.WriteLine($"Methods: {wellDocumentedMethods} of {Methods.Count} ({methodCoverage:P0}) methods"); + Console.WriteLine($"Fields: {wellDocumentedFields} of {Fields.Count} ({fieldCoverage:P0}) fields"); + Console.WriteLine($"Events: {wellDocumentedEvents} of {Events.Count} ({eventCoverage:P0}) events/EventCallback"); Console.WriteLine(); - - if (UnresolvedTypes.Count > 0) - { - Console.WriteLine($"API Builder: WARNING: {UnresolvedTypes.Count} types have XML documentation which couldn't be matched to a type."); - } - if (UnresolvedProperties.Count > 0) - { - Console.WriteLine($"API Builder: WARNING: {UnresolvedProperties.Count} properties have XML documentation which couldn't be matched to a property."); - } - if (UnresolvedMethods.Count > 0) - { - Console.WriteLine($"API Builder: WARNING: {UnresolvedMethods.Count} methods have XML documentation which couldn't be matched to a method."); - } - if (UnresolvedEvents.Count > 0) - { - Console.WriteLine($"API Builder: WARNING: {UnresolvedEvents.Count} events have XML documentation which couldn't be matched to an event."); - } - if (UnresolvedFields.Count > 0) - { - Console.WriteLine($"API Builder: WARNING: {UnresolvedFields.Count} fields have XML documentation which couldn't be matched to a field."); - } } /// @@ -917,29 +761,4 @@ public void AddGlobalsToDocument() /// [GeneratedRegex(@"MudBlazor\.MudGlobal\+([ \S]*)Defaults\.")] private static partial Regex GlobalComponentNameRegEx(); - - /// - /// The regular expression used to extract XML documentation summaries. - /// - [GeneratedRegex(@"\s*([ \S]*)\s*<\/summary>")] - private static partial Regex SummaryRegEx(); - - /// - /// The regular expression used to extract XML documentation remarks. - /// - [GeneratedRegex(@"\s*([ \S]*)\s*<\/remarks>")] - private static partial Regex RemarksRegEx(); - - /// - /// The regular expression used to extract XML documentation return values. - /// - [GeneratedRegex(@"\s*([ \S]*)\s*<\/returns>")] - private static partial Regex ReturnsRegEx(); - - /// - /// The regular expression used to calculate the XML member key. - /// - /// - [GeneratedRegex(@"\[.*\]")] - private static partial Regex TypeFullNameRegEx(); } diff --git a/src/MudBlazor.Docs.Compiler/ApiDocumentationWriter.cs b/src/MudBlazor.Docs.Compiler/ApiDocumentationWriter.cs index 6fdee5908f48..2fdb52c0169d 100644 --- a/src/MudBlazor.Docs.Compiler/ApiDocumentationWriter.cs +++ b/src/MudBlazor.Docs.Compiler/ApiDocumentationWriter.cs @@ -2,13 +2,6 @@ // MudBlazor 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; -using System.IO; -using System.Linq; -using System.Text.RegularExpressions; - namespace MudBlazor.Docs.Compiler; /// @@ -51,8 +44,6 @@ public void WriteHeader() WriteLine("// "); WriteLine("//-----------------------------------------------------------------------"); WriteLine(); - WriteLine("using System.Collections.Frozen;"); - WriteLine("using System.Collections.Generic;"); WriteLine("using System.CodeDom.Compiler;"); WriteLine(); WriteLine("namespace MudBlazor.Docs.Models;"); @@ -134,7 +125,7 @@ public void WriteLineIndented(string text) public void WriteConstructorEnd() { Outdent(); - WriteLine("}"); + WriteLineIndented("}"); } /// @@ -167,7 +158,7 @@ public void Outdent() /// /// /// - public static string Escape(string code) => code?.Replace("\"", "\\\""); + public static string Escape(string code) => code?.Replace("\"", "\"\""); /// /// Writes the category for the member. @@ -187,7 +178,8 @@ public void WriteCategory(string category) /// The category order (derived from ). public void WriteOrder(int? order) { - if (order.HasValue) + // Wirte if the order is present, but not int.MaxValue (which is the default) + if (order.HasValue && order.Value != int.MaxValue) { Write($"Order = {order}, "); } @@ -201,19 +193,19 @@ public void WriteSummary(string summary) { if (!string.IsNullOrEmpty(summary)) { - Write($"Summary = \"{Escape(summary)}\", "); + Write($"Summary = @\"{Escape(summary)}\", "); } } /// /// Serializes an XML summary for a member. /// - /// - public void WriteSummaryIndented(string remarks) + /// + public void WriteSummaryIndented(string summary) { - if (!string.IsNullOrEmpty(remarks)) + if (!string.IsNullOrEmpty(summary)) { - WriteLineIndented($"Summary = \"{Escape(remarks)}\", "); + WriteLineIndented($"Summary = @\"{Escape(summary)}\", "); } } @@ -225,7 +217,7 @@ public void WriteRemarks(string remarks) { if (!string.IsNullOrEmpty(remarks)) { - WriteLine($"Remarks = \"{Escape(remarks)}\", "); + Write($"Remarks = @\"{Escape(remarks)}\", "); } } @@ -233,11 +225,35 @@ public void WriteRemarks(string remarks) /// Serializes an XML remarks for a member. /// /// + public void WriteLineRemarks(string remarks) + { + if (!string.IsNullOrEmpty(remarks)) + { + WriteLine($"Remarks = @\"{Escape(remarks)}\", "); + } + } + + /// + /// Serializes the XML remarks for a member. + /// + /// public void WriteRemarksIndented(string remarks) { if (!string.IsNullOrEmpty(remarks)) { - WriteLineIndented($"Remarks = \"{Escape(remarks)}\", "); + WriteLineIndented($"Remarks = @\"{Escape(remarks)}\", "); + } + } + + /// + /// Serializes the XML remarks for a method return value. + /// + /// The XML docs for the method's return value. + public void WriteReturns(string returns) + { + if (!string.IsNullOrEmpty(returns)) + { + Write($"Returns = @\"{Escape(returns)}\", "); } } @@ -248,13 +264,119 @@ public void WriteRemarksIndented(string remarks) public void WriteTypes(IDictionary types) { WriteLineIndented("// Build all of the documented types"); - WriteLineIndented($"Types = new Dictionary();"); + WriteLineIndented($"Types = new()"); + WriteLineIndented("{"); + Indent(); foreach (var type in types) { WriteType(type.Value); } + Outdent(); + WriteLineIndented("};"); + + WriteLine(); + } + + /// + /// Links all properties to their declaring types. + /// + public void LinkDocumentedTypes(IDictionary properties) + { + WriteLineIndented("// Link properties to their declaring types"); + + foreach (var property in properties) + { + if (property.Value.DeclaringDocumentedType != null) + { + // Link directly to a documented type + WriteLineIndented($"Properties[\"{property.Key}\"].DeclaringType = Types[\"{property.Value.DeclaringDocumentedType.Key}\"];"); + } + else + { + // For external .NET types like ComponentBase, just set the name + WriteLineIndented($"Properties[\"{property.Key}\"].DeclaringTypeName = \"{property.Value.DeclaringType.Name}\";"); + } + if (property.Value.ChangeEvent != null) + { + WriteLineIndented($"Properties[\"{property.Key}\"].ChangeEvent = Events[\"{property.Value.ChangeEvent.Key}\"];"); + } + } + + WriteLine(); + } + + /// + /// Links all properties to their declaring types. + /// + public void LinkDocumentedTypes(IDictionary fields) + { + WriteLineIndented("// Link fields to their declaring types"); + + foreach (var field in fields) + { + if (field.Value.DeclaringDocumentedType != null) + { + WriteLineIndented($"Fields[\"{field.Key}\"].DeclaringType = Types[\"{field.Value.DeclaringDocumentedType.Key}\"];"); + } + else + { + // For external .NET types like ComponentBase, just set the name + WriteLineIndented($"Fields[\"{field.Key}\"].DeclaringTypeName = \"{field.Value.DeclaringType.Name}\";"); + } + } + + WriteLine(); + } + + /// + /// Links all events to their declaring types. + /// + public void LinkDocumentedTypes(IDictionary events) + { + WriteLineIndented("// Link events to their declaring types"); + + foreach (var eventItem in events) + { + if (eventItem.Value.DeclaringDocumentedType != null) + { + WriteLineIndented($"Events[\"{eventItem.Key}\"].DeclaringType = Types[\"{eventItem.Value.DeclaringDocumentedType.Key}\"];"); + } + else + { + // For external .NET types like ComponentBase, just set the name + WriteLineIndented($"Events[\"{eventItem.Key}\"].DeclaringTypeName = \"{eventItem.Value.DeclaringType.Name}\";"); + } + if (eventItem.Value.Property != null) + { + WriteLineIndented($"Events[\"{eventItem.Key}\"].Property = Properties[\"{eventItem.Value.Property.Key}\"];"); + } + } + + WriteLine(); + } + + /// + /// Links all events to their declaring types. + /// + public void LinkDocumentedTypes(IDictionary methods) + { + WriteLineIndented("// Link methods to their declaring types"); + + foreach (var method in methods) + { + if (method.Value.DeclaringDocumentedType != null) + { + WriteLineIndented($"Methods[\"{method.Key}\"].DeclaringType = Types[\"{method.Value.DeclaringDocumentedType.Key}\"];"); + } + else + { + // For external .NET types like ComponentBase, just set the name + WriteLineIndented($"Methods[\"{method.Key}\"].DeclaringTypeName = \"{method.Value.DeclaringType.Name}\";"); + } + } + WriteLine(); } @@ -264,11 +386,12 @@ public void WriteTypes(IDictionary types) /// The type to serialize. public void WriteType(DocumentedType type) { - WriteIndented($"Types.Add(\"{type.Key}\", new()"); + WriteIndented("{ "); + Write($"\"{type.Key}\", new()"); WriteLine(" {"); Indent(); WriteLineIndented($"Name = \"{type.Name}\", "); - WriteLineIndented($"NameFriendly = \"{GetFriendlyTypeName(type.Type)}\", "); + WriteLineIndented($"NameFriendly = \"{type.Type.GetFriendlyName()}\", "); WriteBaseTypeIndented(type.BaseType); WriteIsComponentIndented(type.Type.IsSubclassOf(typeof(MudComponentBase))); WriteSummaryIndented(type.Summary); @@ -277,8 +400,10 @@ public void WriteType(DocumentedType type) WriteGlobalSettings(type); WriteFields(type); WriteMethods(type); + WriteEvents(type); Outdent(); - WriteLineIndented("});"); + WriteIndented("}"); + WriteLine("},"); } /// @@ -288,13 +413,18 @@ public void WriteType(DocumentedType type) public void WriteEvents(IDictionary events) { WriteLineIndented("// Build all of the documented events"); - WriteLineIndented($"Events = new Dictionary();"); + WriteLineIndented($"Events = new()"); + WriteLineIndented("{"); + Indent(); foreach (var documentedEvent in events) { WriteEvent(documentedEvent.Value); } + Outdent(); + WriteLineIndented("};"); + WriteLine(); } @@ -304,18 +434,20 @@ public void WriteEvents(IDictionary events) /// The event to serialize. public void WriteEvent(DocumentedEvent documentedEvent) { - WriteIndented($"Events.Add(\"{documentedEvent.Key}\", new()"); + WriteIndented("{ "); + Write($"\"{documentedEvent.Key}\", new()"); Write(" { "); Write($"Name = \"{documentedEvent.Name}\", "); Write($"TypeName = \"{documentedEvent.Type.FullName}\", "); - Write($"TypeFriendlyName = \"{GetFriendlyTypeName(documentedEvent.Type)}\", "); - WriteDeclaringType(documentedEvent); + Write($"TypeFriendlyName = \"{documentedEvent.Type.GetFriendlyName()}\", "); WriteCategory(documentedEvent.Category); WriteOrder(documentedEvent.Order); + WriteIsParameter(documentedEvent.IsParameter); + WriteIsProtected(documentedEvent.IsProtected); WriteSummary(documentedEvent.Summary); WriteRemarks(documentedEvent.Remarks); - Write(" }"); - WriteLine(");"); + Write("}"); + WriteLine("},"); } /// @@ -325,13 +457,18 @@ public void WriteEvent(DocumentedEvent documentedEvent) public void WriteFields(IDictionary fields) { WriteLineIndented("// Build all of the documented fields"); - WriteLineIndented($"Fields = new Dictionary();"); + WriteLineIndented($"Fields = new()"); + WriteLineIndented("{"); + Indent(); foreach (var field in fields) { WriteField(field.Value); } + Outdent(); + WriteLineIndented("};"); + WriteLine(); } @@ -341,18 +478,19 @@ public void WriteFields(IDictionary fields) /// The field to serialize. public void WriteField(DocumentedField field) { - WriteIndented($"Fields.Add(\"{field.Key}\", new()"); + WriteIndented("{ "); + Write($"\"{field.Key}\", new()"); Write(" { "); Write($"Name = \"{field.Name}\", "); Write($"TypeName = \"{field.Type.FullName}\", "); - Write($"TypeFriendlyName = \"{GetFriendlyTypeName(field.Type)}\", "); - WriteDeclaringType(field); + Write($"TypeFriendlyName = \"{field.Type.GetFriendlyName()}\", "); WriteCategory(field.Category); + WriteIsProtected(field.IsProtected); WriteOrder(field.Order); WriteSummary(field.Summary); WriteRemarks(field.Remarks); - Write(" }"); - WriteLine(");"); + Write("}"); + WriteLine("},"); } /// @@ -362,16 +500,18 @@ public void WriteField(DocumentedField field) public void WriteProperties(IDictionary properties) { WriteLineIndented("// Build all of the documented properties"); - WriteLineIndented($"Properties = new Dictionary();"); + WriteLineIndented("Properties = new()"); + WriteLineIndented("{"); + Indent(); foreach (var property in properties) { - if (!ApiDocumentationBuilder.IsExcluded(property.Value.Type)) - { - WriteProperty(property.Value); - } + WriteProperty(property.Value); } + Outdent(); + WriteLineIndented("};"); + WriteLine(); } @@ -381,19 +521,48 @@ public void WriteProperties(IDictionary properties) /// the property to serialize. public void WriteProperty(DocumentedProperty property) { - WriteIndented($"Properties.Add(\"{property.Key}\", new()"); + WriteIndented("{ "); + Write($"\"{property.Key}\", new()"); Write(" { "); Write($"Name = \"{property.Name}\", "); Write($"TypeName = \"{property.Type.FullName}\", "); - Write($"TypeFriendlyName = \"{GetFriendlyTypeName(property.Type)}\", "); - WriteDeclaringType(property); + Write($"TypeFriendlyName = \"{property.Type.GetFriendlyName()}\", "); WriteCategory(property.Category); - WriteOrder(property.Order); WriteIsParameter(property.IsParameter); - WriteSummary(property.Summary); + WriteIsProtected(property.IsProtected); + WriteOrder(property.Order); WriteRemarks(property.Remarks); - Write(" }"); - WriteLine(");"); + WriteSummary(property.Summary); + Write("}"); + WriteLine("},"); + } + + /// + /// Serializes the parameters of methods. + /// + /// + public void WriteMethodParameters(List parameters) + { + if (parameters.Count == 0) + { + return; + } + + WriteLine("Parameters = "); + + Indent(); + WriteLineIndented("["); + Indent(); + + foreach (var parameter in parameters) + { + WriteMethodParameter(parameter); + } + + Outdent(); + WriteLineIndented("],"); + Outdent(); + WriteIndent(); } /// @@ -422,9 +591,9 @@ public void WriteProperties(DocumentedType type) WriteLineIndented("Properties = { "); Indent(); - foreach (var property in type.Properties) + foreach (var pair in type.Properties) { - WriteProperty(type, property.Value); + WriteTypeProperty(pair.Value); } Outdent(); @@ -459,7 +628,7 @@ public void WriteGlobalSettings(DocumentedType type) foreach (var property in type.GlobalSettings) { - WriteProperty(type, property.Value); + WriteTypeProperty(property.Value); } Outdent(); @@ -469,27 +638,48 @@ public void WriteGlobalSettings(DocumentedType type) /// /// Serializes the specified property. /// - /// The current type being serialized. /// The property to serialize. - public void WriteProperty(DocumentedType type, DocumentedProperty property) + public void WriteTypeProperty(DocumentedProperty property) { WriteIndented("{ "); Write($"\"{property.Name}\", Properties[\"{property.Key}\"]"); WriteLine(" },"); } + /// + /// Serializes the specified event. + /// + /// The event to serialize. + public void WriteTypeEvent(DocumentedEvent eventItem) + { + WriteIndented("{ "); + Write($"\"{eventItem.Name}\", Events[\"{eventItem.Key}\"]"); + WriteLine(" },"); + } + /// /// Serializes the specified field. /// - /// The current type being serialized. - /// The property to serialize. - public void WriteField(DocumentedType type, DocumentedField field) + /// The field to serialize. + public void WriteTypeField(DocumentedField field) { WriteIndented("{ "); Write($"\"{field.Name}\", Fields[\"{field.Key}\"]"); WriteLine(" },"); } + /// + /// Serializes the specified method. + /// + /// The current type being serialized. + /// The method to serialize. + public void WriteTypeMethod(DocumentedMethod method) + { + WriteIndented("{ "); + Write($"\"{method.Name}\", Methods[\"{method.Key}\"]"); + WriteLine(" },"); + } + /// /// Serializes the specified methods. /// @@ -497,17 +687,17 @@ public void WriteField(DocumentedType type, DocumentedField field) public void WriteMethods(IDictionary methods) { WriteLineIndented("// Build all of the documented methods"); - WriteLineIndented($"Methods = new Dictionary();"); + WriteLineIndented($"Methods = new()"); + WriteLineIndented("{"); + Indent(); foreach (var method in methods) { - // Skip excluded methods and internally generated methods - if (!ApiDocumentationBuilder.ExcludedMethods.Contains(method.Value.Name) && !method.Value.Name.StartsWith('<')) - { - WriteMethod(method.Value); - } + WriteMethod(method.Value); } + Outdent(); + WriteLineIndented("};"); WriteLine(); } @@ -529,16 +719,18 @@ public void WriteMethods(DocumentedType type) */ + // Anything to do? + if (type.Methods.Count == 0) + { + return; + } + WriteLineIndented("Methods = { "); Indent(); foreach (var method in type.Methods) { - // Skip excluded methods and internally generated methods - if (!ApiDocumentationBuilder.ExcludedMethods.Contains(method.Value.Name) && !method.Value.Name.StartsWith('<')) - { - WriteMethod(type, method.Value); - } + WriteTypeMethod(method.Value); } Outdent(); @@ -551,29 +743,34 @@ public void WriteMethods(DocumentedType type) /// public void WriteMethod(DocumentedMethod method) { - WriteIndented($"Methods.Add(\"{method.Key}\", new()"); + WriteIndented("{ "); + Write($"\"{method.Key}\", new()"); Write(" { "); Write($"Name = \"{method.Name}\", "); WriteReturnType(method); - WriteDeclaringType(method); WriteCategory(method.Category); + WriteIsProtected(method.IsProtected); WriteOrder(method.Order); WriteSummary(method.Summary); WriteRemarks(method.Remarks); - Write(" }"); - WriteLine(");"); + WriteReturns(method.Returns); + WriteMethodParameters(method.Parameters); + Write("}"); + WriteLine("},"); } /// - /// Serializes the specified method. + /// Serializes the specified property. /// - /// The current type being serialized. - /// The method to serialize. - public void WriteMethod(DocumentedType type, DocumentedMethod method) + /// The property to serialize. + public void WriteMethodParameter(DocumentedParameter parameter) { - WriteIndented("{ "); - Write($"\"{method.Name}\", Methods[\"{method.Key}\"]"); - WriteLine(" },"); + WriteIndented("new() { "); + Write($"Name = \"{parameter.Name}\", "); + Write($"TypeName = \"{parameter.Type.FullName}\", "); + Write($"TypeFriendlyName = \"{parameter.Type.GetFriendlyName()}\", "); + WriteSummary(parameter.Summary); + WriteLine("}, "); } /// @@ -597,7 +794,7 @@ public void WriteIsComponentIndented(bool isComponent) public void WriteReturnType(DocumentedMethod method) { Write($"TypeName = \"{Escape(method.Type.Name)}\", "); - Write($"TypeFriendlyName = \"{GetFriendlyTypeName(method.Type)}\", "); + Write($"TypeFriendlyName = \"{method.Type.GetFriendlyName()}\", "); } /// @@ -612,6 +809,18 @@ public void WriteIsParameter(bool isParameter) } } + /// + /// Writes whether a property is protected. + /// + /// + public void WriteIsProtected(bool isProtected) + { + if (isProtected) + { + Write($"IsProtected = true, "); + } + } + /// /// Writes the name of the given base type. /// @@ -625,40 +834,26 @@ public void WriteBaseTypeIndented(Type baseType) } /// - /// Writes the declaring type of an event. + /// Serializes all fields for the specified type. /// - /// The event to serialize. - public void WriteDeclaringType(DocumentedEvent documentedEvent) + /// The type being serialized. + public void WriteEvents(DocumentedType type) { - Write($"DeclaringTypeName = \"{Escape(documentedEvent.DeclaringTypeFullName)}\", "); - } + if (type.Events.Count == 0) + { + return; + } - /// - /// Writes the declaring type of a property. - /// - /// The property to serialize. - public void WriteDeclaringType(DocumentedProperty property) - { - Write($"DeclaringTypeName = \"{Escape(property.DeclaringTypeFullName)}\", "); - } + WriteLineIndented("Events = { "); + Indent(); - /// - /// Writes the declaring type of a property. - /// - /// The property to serialize. - public void WriteDeclaringType(DocumentedField field) - { - Write($"DeclaringTypeName = \"{Escape(field.DeclaringTypeFullName)}\", "); - } + foreach (var field in type.Events) + { + WriteTypeEvent(field.Value); + } - /// - /// Writes the type in which the property was declared, if it's another type. - /// - /// The type containing the property. - /// The property being described. - public void WriteDeclaringType(DocumentedMethod method) - { - Write($"DeclaringTypeName = \"{Escape(method.DeclaringTypeFullName)}\", "); + Outdent(); + WriteLineIndented("},"); } /// @@ -677,73 +872,11 @@ public void WriteFields(DocumentedType type) foreach (var field in type.Fields) { - WriteField(type, field.Value); + WriteTypeField(field.Value); } Outdent(); WriteLineIndented("},"); } - /// - /// Gets the C# equivalent of the specified XML type. - /// - /// The type name to convert. - /// - public static string GetFriendlyTypeName(Type type) - { - // Replace value types - var name = type.FullName switch - { - "System.Boolean" => "bool", - "System.Boolean[]" => "bool[]", - "System.Int32" => "int", - "System.Int32[]" => "int[]", - "System.Int64" => "long", - "System.Int64[]" => "long[]", - "System.String" => "string", - "System.String[]" => "string[]", - "System.Double" => "double", - "System.Double[]" => "double[]", - "System.Single" => "float", - "System.Single[]" => "float[]", - "System.Object" => "object", - "System.Void" => "", - _ => type.Name - }; - - // Replace generics - if (type.IsGenericType) - { - // Get the parameters - var parameters = type.GetGenericArguments(); - // Shave off the `1 - name = string.Concat(name.AsSpan(0, name.Length - 2), "<"); - // Simplify all generic parameter - for (var index = 0; index < parameters.Length; index++) - { - if (index > 0) - { - name += ", "; - } - - name += GetFriendlyTypeName(parameters[index]); - } - name += ">"; - } - - // Simplify Nullable to T? - foreach (var match in NullableRegEx().Matches(name).Cast()) - { - name = name.Replace(match.Groups[0].Value, match.Groups[1].Value + "?"); - } - - return name; - } - - /// - /// The regular expression for Nullable - /// - /// - [GeneratedRegex("Nullable<([\\S]*)>")] - private static partial Regex NullableRegEx(); } diff --git a/src/MudBlazor.Docs.Compiler/DocumentedEvent.cs b/src/MudBlazor.Docs.Compiler/DocumentedEvent.cs index ad3f6b5bd007..cd066f7410c9 100644 --- a/src/MudBlazor.Docs.Compiler/DocumentedEvent.cs +++ b/src/MudBlazor.Docs.Compiler/DocumentedEvent.cs @@ -2,8 +2,6 @@ // MudBlazor licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; - namespace MudBlazor.Docs.Compiler; #nullable enable @@ -13,5 +11,19 @@ namespace MudBlazor.Docs.Compiler; /// public class DocumentedEvent : DocumentedMember { + /// + /// Whether this property is a parameter. + /// + /// + /// When true, the is applied to this property. + /// + public bool IsParameter { get; set; } + /// + /// The property which triggers this event. + /// + /// + /// When set, this event enables binding for a property via @bind-[Property] in Razor. + /// + public DocumentedProperty? Property { get; set; } } diff --git a/src/MudBlazor.Docs.Compiler/DocumentedMember.cs b/src/MudBlazor.Docs.Compiler/DocumentedMember.cs index 378a153a2a28..05c70c75a627 100644 --- a/src/MudBlazor.Docs.Compiler/DocumentedMember.cs +++ b/src/MudBlazor.Docs.Compiler/DocumentedMember.cs @@ -2,7 +2,6 @@ // MudBlazor licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; using System.Diagnostics; namespace MudBlazor.Docs.Compiler; @@ -29,9 +28,9 @@ public abstract class DocumentedMember public Type? DeclaringType { get; set; } /// - /// The name of the type which defines this member. + /// The type which defines this member. /// - public string? DeclaringTypeFullName { get; set; } + public DocumentedType? DeclaringDocumentedType { get; set; } /// /// Whether this member is only visible to inheritors. @@ -46,18 +45,13 @@ public abstract class DocumentedMember /// /// The order of this member relative to other members. /// - public int? Order { get; set; } + public int Order { get; set; } = int.MaxValue; /// /// The unique key for this member in dictionaries. /// public string? Key { get; set; } - /// - /// The unique key for this member in XML documentation. - /// - public string? XmlKey { get; set; } - /// /// The detailed description for this member, and any related information. /// diff --git a/src/MudBlazor.Docs.Compiler/DocumentedMethod.cs b/src/MudBlazor.Docs.Compiler/DocumentedMethod.cs index 516ab839b63a..0ca250e02042 100644 --- a/src/MudBlazor.Docs.Compiler/DocumentedMethod.cs +++ b/src/MudBlazor.Docs.Compiler/DocumentedMethod.cs @@ -2,10 +2,6 @@ // MudBlazor 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; - namespace MudBlazor.Docs.Compiler; #nullable enable @@ -18,7 +14,7 @@ public class DocumentedMethod : DocumentedMember /// /// The parameters for this method. /// - public Dictionary Parameters { get; set; } = []; + public List Parameters { get; set; } = []; /// /// The XML documentation for what this method returns. diff --git a/src/MudBlazor.Docs.Compiler/DocumentedParameter.cs b/src/MudBlazor.Docs.Compiler/DocumentedParameter.cs index dd285c8fa2e6..4389d554de35 100644 --- a/src/MudBlazor.Docs.Compiler/DocumentedParameter.cs +++ b/src/MudBlazor.Docs.Compiler/DocumentedParameter.cs @@ -2,20 +2,28 @@ // MudBlazor licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; using System.Diagnostics; namespace MudBlazor.Docs.Compiler; /// -/// Represents a documented parameter for a method. +/// A parameter for a method. /// -[DebuggerDisplay("({TypeName}) {Name}: {Summary}")] +[DebuggerDisplay("({Type.Name}) {Name}: {Text}")] public sealed class DocumentedParameter { - public string Name { get; set; } + /// + /// The name of this parameter. + /// + public string Name { get; set; } = ""; + + /// + /// The type of this member. + /// public Type Type { get; set; } - public string TypeFullName { get; set; } - public string TypeName { get; set; } - public string Summary { get; set; } + + /// + /// The XML documentation for this parameter. + /// + public string Summary { get; set; } = ""; } diff --git a/src/MudBlazor.Docs.Compiler/DocumentedProperty.cs b/src/MudBlazor.Docs.Compiler/DocumentedProperty.cs index dbd9d0d36c2f..74154002b9cf 100644 --- a/src/MudBlazor.Docs.Compiler/DocumentedProperty.cs +++ b/src/MudBlazor.Docs.Compiler/DocumentedProperty.cs @@ -20,4 +20,12 @@ public sealed class DocumentedProperty : DocumentedMember /// When true, the is applied to this property. /// public bool IsParameter { get; set; } + + /// + /// The called when this property changes. + /// + /// + /// When set, this property can be bound via @bind-[Property] in Razor. + /// + public DocumentedEvent? ChangeEvent { get; set; } } diff --git a/src/MudBlazor.Docs.Compiler/DocumentedType.cs b/src/MudBlazor.Docs.Compiler/DocumentedType.cs index 34442f7e66c5..d0b89390319a 100644 --- a/src/MudBlazor.Docs.Compiler/DocumentedType.cs +++ b/src/MudBlazor.Docs.Compiler/DocumentedType.cs @@ -2,8 +2,6 @@ // MudBlazor 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; namespace MudBlazor.Docs.Compiler; @@ -24,11 +22,6 @@ public class DocumentedType /// public string Key { get; set; } - /// - /// The key for this type for XML documentation. - /// - public string XmlKey { get; set; } - /// /// The XML documentation summary for this type. /// diff --git a/src/MudBlazor.Docs.Compiler/MudBlazor.Docs.Compiler.csproj b/src/MudBlazor.Docs.Compiler/MudBlazor.Docs.Compiler.csproj index 5a147714ecfb..286d2a59d985 100644 --- a/src/MudBlazor.Docs.Compiler/MudBlazor.Docs.Compiler.csproj +++ b/src/MudBlazor.Docs.Compiler/MudBlazor.Docs.Compiler.csproj @@ -7,6 +7,7 @@ + diff --git a/src/MudBlazor.Docs.Compiler/TestsForApiPages.cs b/src/MudBlazor.Docs.Compiler/TestsForApiPages.cs index 477ce694c08a..6ded4cd923f9 100644 --- a/src/MudBlazor.Docs.Compiler/TestsForApiPages.cs +++ b/src/MudBlazor.Docs.Compiler/TestsForApiPages.cs @@ -197,14 +197,22 @@ public bool Execute() /// public void WritePublicTypeTests(CodeBuilder cb) { - var mudBlazorComponents = typeof(_Imports).Assembly.GetTypes().Where(type => type.IsPublic); + var mudBlazorAssembly = typeof(_Imports).Assembly; + var mudBlazorComponents = mudBlazorAssembly.GetTypes() + .Where(type => + // Include public types + type.IsPublic + // ... which aren't excluded + && !ApiDocumentationBuilder.IsExcluded(type) + // ... which aren't interfaces + && !type.IsInterface + // ... which aren't source generators + && !type.Name.Contains("SourceGenerator") + // ... which aren't extension classes + && !type.Name.Contains("Extensions")) + .ToList(); foreach (var type in mudBlazorComponents) { - if (ApiDocumentationBuilder.IsExcluded(type)) - { - continue; - } - // Skip MudBlazor.Color and MudBlazor.Input types if (type.Name == "Color" || type.Name == "Input") { diff --git a/src/MudBlazor.Docs.Compiler/TypeExtensions.cs b/src/MudBlazor.Docs.Compiler/TypeExtensions.cs new file mode 100644 index 000000000000..c653a0f92a42 --- /dev/null +++ b/src/MudBlazor.Docs.Compiler/TypeExtensions.cs @@ -0,0 +1,80 @@ +// Copyright (c) MudBlazor 2021 +// MudBlazor licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Text.RegularExpressions; + +namespace MudBlazor.Docs.Compiler; + +/// +/// Methods added to the class. +/// +public static partial class TypeExtensions +{ + /// + /// Gets the shorthand name for this type. + /// + public static string GetFriendlyName(this Type type) + { + // Replace value types + var name = type.FullName switch + { + "System.Boolean" => "bool", + "System.Boolean[]" => "bool[]", + "System.Int32" => "int", + "System.Int32&" => "ref int", + "System.Int32[]" => "int[]", + "System.Int64" => "long", + "System.Int64&" => "ref long", + "System.Int64[]" => "long[]", + "System.String" => "string", + "System.String&" => "ref string", + "System.String[]" => "string[]", + "System.Double" => "double", + "System.Double&" => "ref double", + "System.Double[]" => "double[]", + "System.Single" => "float", + "System.Single&" => "ref float", + "System.Single[]" => "float[]", + "System.Object" => "object", + "System.Void" => "", + _ => type.Name + }; + + // Replace generics + if (type.IsGenericType) + { + // Get the parameters + var parameters = type.GetGenericArguments(); + // Shave off the `1 + name = string.Concat(name.AsSpan(0, name.Length - 2), "<"); + // Simplify all generic parameter + for (var index = 0; index < parameters.Length; index++) + { + if (index > 0) + { + name += ", "; + } + + name += GetFriendlyName(parameters[index]); + } + name += ">"; + } + + // Simplify Nullable to T? + foreach (var match in NullableRegEx().Matches(name).Cast()) + { + name = name.Replace(match.Groups[0].Value, match.Groups[1].Value + "?"); + } + + return name; + } + + /// + /// The regular expression for Nullable + /// + /// + [GeneratedRegex("Nullable<([\\S]*)>")] + private static partial Regex NullableRegEx(); +} diff --git a/src/MudBlazor.Docs.Server/Program.cs b/src/MudBlazor.Docs.Server/Program.cs index 79f5c175b741..ce7b38176746 100644 --- a/src/MudBlazor.Docs.Server/Program.cs +++ b/src/MudBlazor.Docs.Server/Program.cs @@ -1,4 +1,5 @@ using MudBlazor.Docs.Extensions; +using MudBlazor.Docs.Models; using MudBlazor.Docs.Services; using MudBlazor.Docs.Services.Notifications; @@ -47,6 +48,8 @@ { inMemoryService.Preload(); } + // Warm up the documentation + ApiDocumentation.GetType("MudAlert"); } app.Run(); diff --git a/src/MudBlazor.Docs.Wasm/Program.cs b/src/MudBlazor.Docs.Wasm/Program.cs index 80fee7c559a7..1c1be8187e5a 100644 --- a/src/MudBlazor.Docs.Wasm/Program.cs +++ b/src/MudBlazor.Docs.Wasm/Program.cs @@ -5,6 +5,7 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.JSInterop; using MudBlazor.Docs.Extensions; +using MudBlazor.Docs.Models; using MudBlazor.Docs.Services.Notifications; using MudBlazor.Docs.Wasm; @@ -32,5 +33,7 @@ { inMemoryService.Preload(); } +// Warm up the documentation +ApiDocumentation.GetType("MudAlert"); await build.RunAsync(); diff --git a/src/MudBlazor.Docs.WasmHost/Program.cs b/src/MudBlazor.Docs.WasmHost/Program.cs index f13241bd56c6..ee8788d5c194 100644 --- a/src/MudBlazor.Docs.WasmHost/Program.cs +++ b/src/MudBlazor.Docs.WasmHost/Program.cs @@ -5,6 +5,7 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using MudBlazor.Docs.Extensions; +using MudBlazor.Docs.Models; using MudBlazor.Docs.Services; using MudBlazor.Docs.Services.Notifications; using MudBlazor.Docs.WasmHost.Prerender; @@ -69,6 +70,9 @@ var crawlerIdentifier = scope.ServiceProvider.GetRequiredService(); await crawlerIdentifier.Initialize(); + + // Warm up the documentation + ApiDocumentation.GetType("MudAlert"); } app.Run(); diff --git a/src/MudBlazor.Docs/Components/ApiBreadcrumbs.razor.cs b/src/MudBlazor.Docs/Components/ApiBreadcrumbs.razor.cs index fc3bfe5eb8b0..559a46c228c5 100644 --- a/src/MudBlazor.Docs/Components/ApiBreadcrumbs.razor.cs +++ b/src/MudBlazor.Docs/Components/ApiBreadcrumbs.razor.cs @@ -2,13 +2,6 @@ // MudBlazor 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; -using System.Linq; -using System.Text; -using System.Threading; -using System.Threading.Tasks; using Microsoft.AspNetCore.Components; using MudBlazor.Docs.Models; diff --git a/src/MudBlazor.Docs/Components/ApiGlobalSettingTable.razor.cs b/src/MudBlazor.Docs/Components/ApiGlobalSettingTable.razor.cs index 026746efdece..62736c637f92 100644 --- a/src/MudBlazor.Docs/Components/ApiGlobalSettingTable.razor.cs +++ b/src/MudBlazor.Docs/Components/ApiGlobalSettingTable.razor.cs @@ -2,13 +2,6 @@ // MudBlazor 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; -using System.Linq; -using System.Text; -using System.Threading; -using System.Threading.Tasks; using Microsoft.AspNetCore.Components; using MudBlazor.Docs.Models; @@ -102,8 +95,8 @@ public TableGroupDefinition CurrentGroups return CurrentGrouping switch { ApiMemberGrouping.Categories => new() { Selector = (property) => property.Category ?? "" }, - ApiMemberGrouping.Inheritance => new() { Selector = (property) => property.DeclaringType?.Name ?? "" }, - _ => new() { Selector = (property) => property.Category ?? "" } + ApiMemberGrouping.Inheritance => new() { Selector = (property) => property.DeclaringType?.NameFriendly ?? "" }, + _ => new() { Selector = (property) => "" }, }; } } diff --git a/src/MudBlazor.Docs/Components/ApiMemberTable.razor b/src/MudBlazor.Docs/Components/ApiMemberTable.razor index 2f0a4eae7e47..bba2af3b9e89 100644 --- a/src/MudBlazor.Docs/Components/ApiMemberTable.razor +++ b/src/MudBlazor.Docs/Components/ApiMemberTable.razor @@ -1,14 +1,14 @@  + Elevation="0" Class="mud-width-full" Hover="true" Dense="true" + AllowUnsorted="false" GroupBy="@CurrentGroups"> - @if (CurrentGrouping == ApiMemberGrouping.Inheritance) + @if (Grouping == ApiMemberGrouping.Inheritance) { @context.Key } - else if (CurrentGrouping == ApiMemberGrouping.Categories) + else if (Grouping == ApiMemberGrouping.Categories) { @(context.Key ?? "General") @@ -18,11 +18,72 @@ Name Type - Description + Description + + + + + None + Category + Inheritance + + + @if (HasProtected()) + { + @* There are protected members. Show a "Show Protected" switch *@ + + + + + Show Protected + + } + else + { + @* There are no protected members to hide *@ + + + + } + + - @if (context.DeclaringType != null && context.DeclaringType.Name != Type.Name) + @if (Mode == ApiMemberTableMode.Methods) + { + @($"{context.Name}(") + var parameters = ((DocumentedMethod)context).Parameters; + @for (int index = 0; index < parameters.Count; index++) + { + var parameter = parameters[index]; + @if (index > 0) + { + , + } + + + @parameter.Name + + + + + Parameter Name + Type + Summary + + + @parameter.Name + + + + + + + } + @(")") + } + else if (context.DeclaringType != null && context.DeclaringType.Name != Type.Name) { @context.Name @@ -32,13 +93,48 @@ { @context.Name } + @if (Mode == ApiMemberTableMode.Properties) + { + var property = context as DocumentedProperty; + if (property.ChangeEvent != null && ShowBindable) + { + + + + } + } + else if (Mode == ApiMemberTableMode.Events) + { + var eventItem = context as DocumentedEvent; + if (eventItem.Property != null && ShowBindable) + { + + + + } + } + @if (context.IsProtected) + { + + + + } - - - + @if (Mode == ApiMemberTableMode.Methods && !string.IsNullOrEmpty(((DocumentedMethod)context).Returns)) + { + + + + } + else + { + + + + } No members match the current filters. diff --git a/src/MudBlazor.Docs/Components/ApiMemberTable.razor.cs b/src/MudBlazor.Docs/Components/ApiMemberTable.razor.cs index adf73fbf3f6a..1b400c174f4d 100644 --- a/src/MudBlazor.Docs/Components/ApiMemberTable.razor.cs +++ b/src/MudBlazor.Docs/Components/ApiMemberTable.razor.cs @@ -2,10 +2,6 @@ // MudBlazor licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System.Collections.Generic; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; using Microsoft.AspNetCore.Components; using MudBlazor.Docs.Models; @@ -18,22 +14,32 @@ namespace MudBlazor.Docs.Components; /// public partial class ApiMemberTable { + private DocumentedType? _type; + /// /// This table. /// public MudTable? Table { get; set; } /// - /// The name of the type to display. + /// The text to search for. /// - [Parameter] - [EditorRequired] - public string? TypeName { get; set; } + public string? Keyword { get; set; } /// /// The type to display members for. /// - public DocumentedType? Type { get; set; } + [Parameter] + [EditorRequired] + public DocumentedType? Type + { + get => _type; + set + { + _type = value; + Table?.ReloadServerData(); + } + } /// /// The kind of member to display. @@ -45,23 +51,41 @@ public partial class ApiMemberTable /// /// The currently selected grouping. /// - public ApiMemberGrouping CurrentGrouping { get; set; } = ApiMemberGrouping.Categories!; + [Parameter] + public ApiMemberGrouping Grouping { get; set; } = ApiMemberGrouping.Categories; - /// - protected override async Task OnParametersSetAsync() + /// + /// Shows a bindable icon for properties or events which support @bind-. + /// + [Parameter] + public bool ShowBindable { get; set; } = true; + + /// + /// Shows an icon for properties marked with [Parameter]. + /// + [Parameter] + public bool ShowParameters { get; set; } = false; + + /// + /// Shows members marked as protected. + /// + [Parameter] + public bool ShowProtected { get; set; } = false; + + /// + /// Checks if there are protected members of a certain type. + /// + /// When true, there are protected members for the current . + public bool HasProtected() { - // Has the type to display changed? - if (Type == null || Type.Name != TypeName) + return Mode switch { - // Load the new type - Type = ApiDocumentation.GetType(TypeName); - // Is a table available? - if (Table != null) - { - // Yup. Reload it - await Table.ReloadServerData(); - } - } + ApiMemberTableMode.Properties => Type!.Properties.Any(property => property.Value.IsProtected), + ApiMemberTableMode.Methods => Type!.Methods.Any(property => property.Value.IsProtected), + ApiMemberTableMode.Events => Type!.Events.Any(property => property.Value.IsProtected), + ApiMemberTableMode.Fields => Type!.Fields.Any(property => property.Value.IsProtected), + _ => false, + }; } /// @@ -70,11 +94,11 @@ protected override async Task OnParametersSetAsync() /// The current table state. /// A for aborting ongoing requests. /// - public async Task> GetData(TableState state, CancellationToken token) + public Task> GetData(TableState state, CancellationToken token) { if (Type == null || Mode == ApiMemberTableMode.None) { - return new TableData { }; + return Task.FromResult(new TableData() { Items = [] }); } // Get members for the desired mode @@ -87,20 +111,62 @@ public async Task> GetData(TableState state, Cancell _ => new List().AsQueryable(), }; + // Is there a keyword? + if (!string.IsNullOrWhiteSpace(Keyword)) + { + members = members.Where(member => member.Name.Contains(Keyword, StringComparison.OrdinalIgnoreCase) + || (member.Summary != null && member.Summary.Contains(Keyword, StringComparison.OrdinalIgnoreCase)) + || (member.Remarks != null && member.Remarks.Contains(Keyword, StringComparison.OrdinalIgnoreCase)) + ); + } + + // Are we excluding protected members? + if (!ShowProtected) + { + members = members.Where(member => !member.IsProtected); + } + // What's the grouping? - if (CurrentGrouping == ApiMemberGrouping.Categories) + if (Grouping == ApiMemberGrouping.None) { - // Sort by category - var orderedMembers = members.OrderBy(property => property.Order).ThenBy(property => property.Category); + // No group. Just order members by the sort label + members = state.SortLabel switch + { + "Description" => state.SortDirection == SortDirection.Ascending ? members.OrderBy(member => member.Summary) : members.OrderByDescending(member => member.Summary), + "Name" => state.SortDirection == SortDirection.Ascending ? members.OrderBy(member => member.Name) : members.OrderByDescending(member => member.Name), + "Return Type" => state.SortDirection == SortDirection.Ascending ? members.OrderBy(member => member.TypeFriendlyName) : members.OrderByDescending(member => member.TypeFriendlyName), + "Type" => state.SortDirection == SortDirection.Ascending ? members.OrderBy(member => member.TypeFriendlyName) : members.OrderByDescending(member => member.TypeFriendlyName), + _ => state.SortDirection == SortDirection.Ascending ? members.OrderBy(member => member.Name) : members.OrderByDescending(member => member.Name), + }; + } + else if (Grouping == ApiMemberGrouping.Categories) + { + // Sort by member Order (via CategoryAttribute), then by Category name + var orderedMembers = members.OrderBy(member => member.Order).ThenBy(member => member.Category); // ... then by sort column members = state.SortLabel switch { - "Description" => state.SortDirection == SortDirection.Ascending ? orderedMembers.ThenBy(property => property.Summary) : orderedMembers.ThenByDescending(property => property.Summary), - "Name" => state.SortDirection == SortDirection.Ascending ? orderedMembers.ThenBy(property => property.Name) : orderedMembers.ThenByDescending(property => property.Name), - "Return Type" => state.SortDirection == SortDirection.Ascending ? orderedMembers.ThenBy(property => property.TypeFriendlyName) : orderedMembers.ThenByDescending(property => property.TypeFriendlyName), - "Type" => state.SortDirection == SortDirection.Ascending ? orderedMembers.ThenBy(property => property.TypeFriendlyName) : orderedMembers.ThenByDescending(property => property.TypeFriendlyName), - _ => state.SortDirection == SortDirection.Ascending ? orderedMembers.ThenBy(property => property.Name) : orderedMembers.ThenByDescending(property => property.Name), + "Description" => state.SortDirection == SortDirection.Ascending ? orderedMembers.ThenBy(member => member.Summary) : orderedMembers.ThenByDescending(member => member.Summary), + "Name" => state.SortDirection == SortDirection.Ascending ? orderedMembers.ThenBy(member => member.Name) : orderedMembers.ThenByDescending(member => member.Name), + "Return Type" => state.SortDirection == SortDirection.Ascending ? orderedMembers.ThenBy(member => member.TypeFriendlyName) : orderedMembers.ThenByDescending(member => member.TypeFriendlyName), + "Type" => state.SortDirection == SortDirection.Ascending ? orderedMembers.ThenBy(member => member.TypeFriendlyName) : orderedMembers.ThenByDescending(member => member.TypeFriendlyName), + _ => state.SortDirection == SortDirection.Ascending ? orderedMembers.ThenBy(member => member.Name) : orderedMembers.ThenByDescending(member => member.Name), + }; + } + else if (Grouping == ApiMemberGrouping.Inheritance) + { + // Sort by the "inheritance level" (how close the type is to this class), then by Name + var orderedMembers = members.OrderBy(member => GetInheritanceLevel(member.DeclaringType ?? GetDeclaringType(member))).ThenBy(member => GetDeclaringTypeName(member)); + + // ... then by sort column + members = state.SortLabel switch + { + "Description" => state.SortDirection == SortDirection.Ascending ? orderedMembers.ThenBy(member => member.Summary) : orderedMembers.ThenByDescending(member => member.Summary), + "Name" => state.SortDirection == SortDirection.Ascending ? orderedMembers.ThenBy(member => member.Name) : orderedMembers.ThenByDescending(member => member.Name), + "Return Type" => state.SortDirection == SortDirection.Ascending ? orderedMembers.ThenBy(member => member.TypeFriendlyName) : orderedMembers.ThenByDescending(member => member.TypeFriendlyName), + "Type" => state.SortDirection == SortDirection.Ascending ? orderedMembers.ThenBy(member => member.TypeFriendlyName) : orderedMembers.ThenByDescending(member => member.TypeFriendlyName), + _ => state.SortDirection == SortDirection.Ascending ? orderedMembers.ThenBy(member => member.Name) : orderedMembers.ThenByDescending(member => member.Name), }; } @@ -108,25 +174,124 @@ public async Task> GetData(TableState state, Cancell var results = members.ToList(); // What categories are selected? - return await Task.FromResult(new TableData() + return Task.FromResult(new TableData() { Items = results, TotalItems = results.Count, }); } + /// + /// Occurs when has changed. + /// + /// The text to search for. + public Task OnKeywordChangedAsync(string keyword) + { + Keyword = keyword; + return Table!.ReloadServerData(); + } + + /// + /// Occurs when has changed. + /// + /// When true, protected members are displayed. + public Task OnShowProtectedChangedAsync(bool showProtected) + { + ShowProtected = showProtected; + return Table!.ReloadServerData(); + } + + /// + /// Occurs when the table grouping has changed. + /// + /// The new grouping. + public Task OnGroupingChangedAsync(ApiMemberGrouping grouping) + { + Grouping = grouping; + return Table!.ReloadServerData(); + } + + /// + /// Occurs when the table grouping has changed. + /// + /// + public Variant GetGroupingVariant(ApiMemberGrouping grouping) + => Grouping == grouping ? Variant.Filled : Variant.Outlined; + + /// + /// Gets the depth of the specified type relative to this type. + /// + /// The type to compare. + /// The depth of the specified class relative to this class. + public int GetInheritanceLevel(DocumentedType? otherType) + { + // Is no type specified? If so, we can't do anything + if (otherType == null) return 0; + + // Is the other type the same as this? + if (otherType == this.Type) return 0; + + // Walk down to the base class + var baseType = this.Type?.BaseType; + var level = 1; + + // Are we at the specified type? + while (baseType != otherType) + { + // No, go one level deeper + level++; + baseType = baseType!.BaseType; + // Prevent infinite loops just in case + if (baseType == null) + { + break; + } + } + return level; + } + + /// + /// Gets the type which declares this member. + /// + /// The member to examine. + /// + public DocumentedType GetDeclaringType(DocumentedMember member) + { + if (member.DeclaringType != null) + { + return member.DeclaringType; + } + return ApiDocumentation.GetType(member.DeclaringTypeName); + } + + /// + /// Gets the name of this member's declaring type. + /// + /// The member to examine. + /// The name of the type this member is declared in. + /// + /// In some cases, a member may be declared in an external type, such as part of .NET core itself. + /// In these cases, we won't have a set, but we can still calculate the + /// type from the type's name. + /// + public string GetDeclaringTypeName(DocumentedMember member) + { + var declaringType = GetDeclaringType(member); + return declaringType == null ? member.DeclaringTypeName! : declaringType.NameFriendly; + } + /// /// The current groups. /// - public TableGroupDefinition CurrentGroups + public TableGroupDefinition? CurrentGroups { get { - return CurrentGrouping switch + return Grouping switch { ApiMemberGrouping.Categories => new() { Selector = (property) => property.Category ?? "" }, - ApiMemberGrouping.Inheritance => new() { Selector = (property) => property.DeclaringType?.Name ?? "" }, - _ => new() { Selector = (property) => property.Category ?? "" } + ApiMemberGrouping.Inheritance => new() { Selector = (property) => (property.DeclaringType is not null && property.DeclaringType == this.Type) ? "" : $"Inherited from {GetDeclaringTypeName(property)}" }, + _ => null }; } } diff --git a/src/MudBlazor.Docs/Components/ApiText.cs b/src/MudBlazor.Docs/Components/ApiText.cs index 909def37e412..80bbc1e6417b 100644 --- a/src/MudBlazor.Docs/Components/ApiText.cs +++ b/src/MudBlazor.Docs/Components/ApiText.cs @@ -2,17 +2,12 @@ // MudBlazor licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; -using System.Diagnostics; -using System.Text.RegularExpressions; -using System.Threading.Tasks; using System.Xml; using System.Xml.Linq; using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components.Rendering; using MudBlazor.Docs.Extensions; using MudBlazor.Docs.Models; -using MudBlazor.State; namespace MudBlazor.Docs.Components; @@ -21,7 +16,7 @@ namespace MudBlazor.Docs.Components; /// /// Represents the summary or remarks of an object, with linking. /// -public partial class ApiText : ComponentBase +public sealed partial class ApiText : ComponentBase { /// /// The XML documentation text to parse. @@ -30,15 +25,44 @@ public partial class ApiText : ComponentBase [EditorRequired] public string Text { get; set; } = ""; + /// + /// The color of the text. + /// + [Parameter] + public Color Color { get; set; } = Color.Default; + + /// + /// The size of the text. + /// + [Parameter] + public Typo Typo { get; set; } = Typo.caption; + protected override void BuildRenderTree(RenderTreeBuilder builder) { var sequence = 0; - + // Anything to do? + if (string.IsNullOrWhiteSpace(Text)) + { + return; + } // Convert XML documentation text, links, and HTML to MudBlazor equivalents - var xml = XElement.Parse("" + Text + ""); + XElement xml; + try + { + xml = XElement.Parse("" + Text + ""); + } + catch + { + // The XML is malformed somehow. Warn and exit + builder.AddMudText(0, Typo, Color.Warning, "XML documentation error."); + return; + } + // Start with a to wrap properly on mobile + builder.OpenElement(sequence++, "span"); using var reader = xml.CreateReader(); while (reader.Read()) { + var isEmptyElement = reader.IsEmptyElement; switch (reader.NodeType) { case XmlNodeType.Element: @@ -58,25 +82,62 @@ protected override void BuildRenderTree(RenderTreeBuilder builder) var linkRef = link.Substring(2); if (linkType == "T") // Type { - // Add a link to the type - builder.OpenComponent(sequence++); - builder.AddComponentParameter(sequence++, "TypeName", linkRef); - builder.CloseComponent(); + // Is this an external type? + if (linkRef != null && (linkRef.StartsWith("Microsoft", StringComparison.OrdinalIgnoreCase) || linkRef.StartsWith("System", StringComparison.OrdinalIgnoreCase))) + { + // Get the class name and member name + var parts = linkRef.Split("."); + var className = parts[parts.Length - 1].Replace("`1", "").Replace("`2", ""); + // Calculate the Microsoft Docs link + var msLink = linkRef.Replace("`1", "-1").Replace("`2", "-2").ToLowerInvariant(); + builder.AddMudLink(sequence++, $"https://learn.microsoft.com/dotnet/api/{msLink}", className, Typo, "docs-link docs-code docs-code-primary", "_external", (linkSequence, linkBuilder) => + { + linkBuilder.AddContent(linkSequence++, className); + linkBuilder.AddMudTooltip(linkSequence++, Placement.Top, $"External Link", (tooltipSequence, tooltipBuilder) => + { + tooltipBuilder.AddMudIcon(tooltipSequence++, "MudBlazor.Icons.Material.Filled.Link", Color.Default, Size.Small); + }); + }); + } + else + { + // Add a link to the type + builder.OpenComponent(sequence++); + builder.AddComponentParameter(sequence++, "TypeName", linkRef); + builder.AddComponentParameter(sequence++, "Typo", Typo); + builder.CloseComponent(); + } } else // Property, Method, Field, or Event { var member = ApiDocumentation.GetMember(linkRef); if (member != null) { - builder.AddDocumentedMemberLink(sequence++, member); + builder.AddDocumentedMemberLink(sequence++, member, Typo); } else if (linkRef.StartsWith("MudBlazor.Icons")) { - builder.AddMudIcon(sequence++, linkRef, Color.Primary, Size.Medium); + builder.AddMudTooltip(sequence++, Placement.Top, linkRef.Replace("MudBlazor.", ""), (childSequence, childBuilder) => + { + childBuilder.AddMudIcon(childSequence++, linkRef, Color.Primary, Size.Medium); + }); } else if (linkRef != null && (linkRef.StartsWith("Microsoft", StringComparison.OrdinalIgnoreCase) || linkRef.StartsWith("System", StringComparison.OrdinalIgnoreCase))) { - builder.AddMudLink(0, $"https://learn.microsoft.com/dotnet/api/{linkRef}", linkRef, "docs-link docs-code docs-code-primary", "_external"); + // Get the class name and member name + var parts = linkRef.Split("."); + var className = parts[parts.Length - 2].Replace("`1", "").Replace("`2", ""); + var memberName = parts[parts.Length - 1]; + // Calculate the Microsoft Docs link + var msLink = linkRef.Replace("`1", "-1").Replace("`2", "-2").ToLowerInvariant(); + builder.AddMudLink(sequence++, $"https://learn.microsoft.com/dotnet/api/{msLink}", className + "." + memberName, Typo, "docs-link docs-code docs-code-primary", "_external", (linkSequence, linkBuilder) => + { + linkBuilder.AddContent(linkSequence++, className + "." + memberName); + linkBuilder.AddMudTooltip(linkSequence++, Placement.Top, $"External Link", (tooltipSequence, tooltipBuilder) => + { + tooltipBuilder.AddMudIcon(tooltipSequence++, "MudBlazor.Icons.Material.Filled.Link", Color.Default, Size.Small); + }); + }); } else { @@ -85,16 +146,53 @@ protected override void BuildRenderTree(RenderTreeBuilder builder) } break; case "href": - builder.AddMudLink(sequence++, link, link, "docs-link docs-code docs-code-primary", "_external"); + if (string.IsNullOrWhiteSpace(link)) + { + continue; + } + if (isEmptyElement) + { + builder.AddMudLink(sequence++, link, link, Typo, "docs-link docs-code docs-code-primary", "_external", (linkSequence, linkBuilder) => + { + linkBuilder.AddContent(linkSequence++, link); + linkBuilder.AddMudTooltip(linkSequence++, Placement.Top, $"External Link", (tooltipSequence, tooltipBuilder) => + { + tooltipBuilder.AddMudIcon(tooltipSequence++, "MudBlazor.Icons.Material.Filled.Link", Color.Default, Size.Small); + }); + }); + } + else + { + // Move to the link content + reader.Read(); + var text = string.IsNullOrEmpty(reader.Value) ? link : reader.Value; + + builder.AddMudLink(sequence++, link, text, Typo, "docs-link docs-code docs-code-primary", "_external", (linkSequence, linkBuilder) => + { + linkBuilder.AddContent(linkSequence++, text); + linkBuilder.AddMudTooltip(linkSequence++, Placement.Top, $"External Link", (tooltipSequence, tooltipBuilder) => + { + tooltipBuilder.AddMudIcon(tooltipSequence++, "MudBlazor.Icons.Material.Filled.Link", Color.Default, Size.Small); + }); + }); + } break; } break; case "c": // Constant builder.OpenElement(sequence++, "code"); builder.AddAttribute(sequence++, "class", "docs-code docs-code-primary"); + if (isEmptyElement) + { + builder.CloseElement(); + } break; case "para": // Paragraph builder.OpenElement(sequence++, "p"); + if (isEmptyElement) + { + builder.CloseElement(); + } break; } @@ -114,11 +212,10 @@ protected override void BuildRenderTree(RenderTreeBuilder builder) break; case XmlNodeType.Text: // {value} - builder.AddMudText(sequence++, Typo.caption, reader.Value); + builder.AddMudText(sequence++, Typo, Color, reader.Value); break; } } + builder.CloseElement(); // } - - protected override bool ShouldRender() => !string.IsNullOrEmpty(Text); } diff --git a/src/MudBlazor.Docs/Components/ApiTypeHierarchy.razor b/src/MudBlazor.Docs/Components/ApiTypeHierarchy.razor index cf013aca8b93..2824e827ae1f 100644 --- a/src/MudBlazor.Docs/Components/ApiTypeHierarchy.razor +++ b/src/MudBlazor.Docs/Components/ApiTypeHierarchy.razor @@ -5,20 +5,20 @@ @if (context.Value.Name == "Root") { - @context.Text + @context.Text } else { - @if (context.Value.Name == Type.NameFriendly) + @if (context.Value.NameFriendly == Type.NameFriendly) { - @context.Text + @context.Text } else if (!string.IsNullOrEmpty(context.Value.ApiUrl)) { - @context.Text + @context.Text } } diff --git a/src/MudBlazor.Docs/Components/ApiTypeHierarchy.razor.cs b/src/MudBlazor.Docs/Components/ApiTypeHierarchy.razor.cs index e62e99ec62b1..3081ea12360c 100644 --- a/src/MudBlazor.Docs/Components/ApiTypeHierarchy.razor.cs +++ b/src/MudBlazor.Docs/Components/ApiTypeHierarchy.razor.cs @@ -2,10 +2,7 @@ // MudBlazor licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System.Collections.Generic; using System.Collections.ObjectModel; -using System.Diagnostics; -using System.Linq; using Microsoft.AspNetCore.Components; using MudBlazor.Docs.Models; @@ -16,42 +13,27 @@ namespace MudBlazor.Docs.Components; /// /// Represents an inheritance tree for a documented type. /// -public partial class ApiTypeHierarchy +public sealed partial class ApiTypeHierarchy { + private DocumentedType? _type; /// - /// The name of the type to display. + /// The type to display members for. /// [Parameter] [EditorRequired] - public string? TypeName { get; set; } - - /// - /// The type to display members for. - /// - public DocumentedType? Type { get; set; } - - /// - /// The root of the type hierarchy. - /// - public IReadOnlyCollection>? Root { get; set; } - - /// - /// The selected type. - /// - public DocumentedType? SelectedType { get; set; } - - protected override void OnParametersSet() + public DocumentedType? Type { - if (Type == null || Type.Name != TypeName) + get => _type; + set { - Type = ApiDocumentation.GetType(TypeName); + _type = value; SelectedType = Type; // Start with the current type var primaryItem = new TreeItemData { - Text = Type.Name, + Text = Type!.NameFriendly, Selected = true, Expanded = false, Value = Type, @@ -59,7 +41,7 @@ protected override void OnParametersSet() }; var root = new List>() { primaryItem }; // Walk up the hierarchy to build the tree - var parent = Type.BaseType; + var parent = Type!.BaseType; while (parent != null) { root[0] = new TreeItemData() @@ -97,9 +79,23 @@ protected override void OnParametersSet() } // Set the items Root = new ReadOnlyCollection>(root); + StateHasChanged(); } } + /// + /// The root of the type hierarchy. + /// + public IReadOnlyCollection>? Root { get; set; } + + /// + /// The selected type. + /// + public DocumentedType? SelectedType { get; set; } + + /// + /// The navigator for changing to other pages. + /// [Inject] private NavigationManager? Browser { get; set; } @@ -109,7 +105,7 @@ protected override void OnParametersSet() /// public void OnTypeClicked(TreeItemData item) { - if (item.Value != null && !string.IsNullOrEmpty(item.Value.ApiUrl)) + if (item.Value != null && !string.IsNullOrEmpty(item.Value.ApiUrl) && item.Value.Name != "Root") { Browser?.NavigateTo(item.Value.ApiUrl); } diff --git a/src/MudBlazor.Docs/Components/ApiTypeLink.cs b/src/MudBlazor.Docs/Components/ApiTypeLink.cs index 564f52d35a0e..a5c8c7a68234 100644 --- a/src/MudBlazor.Docs/Components/ApiTypeLink.cs +++ b/src/MudBlazor.Docs/Components/ApiTypeLink.cs @@ -2,8 +2,6 @@ // MudBlazor licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; -using System.Diagnostics; using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components.Rendering; using MudBlazor.Docs.Extensions; @@ -16,19 +14,46 @@ namespace MudBlazor.Docs.Components; /// /// A link to an API type, property, method, event, or field. /// -public class ApiTypeLink : ComponentBase +public sealed class ApiTypeLink : ComponentBase { + private DocumentedType? _type; + private string? _typeName; + /// /// The type to link. /// [Parameter] - public DocumentedType? Type { get; set; } + public DocumentedType? Type + { + get => _type; + set + { + if (_type != value) + { + _type = value; + _typeName = _type?.Name; + StateHasChanged(); + } + } + } /// /// The name of the type to link. /// [Parameter] - public string? TypeName { get; set; } + public string? TypeName + { + get => _typeName; + set + { + if (_typeName != value) + { + _typeName = value; + _type = ApiDocumentation.GetType(_typeName); + StateHasChanged(); + } + } + } /// /// The name of the type to display. @@ -42,15 +67,11 @@ public class ApiTypeLink : ComponentBase [Parameter] public bool ShowTooltip { get; set; } = true; - protected override void OnParametersSet() - { - if (Type == null || (TypeName != null && Type.Name.Equals(TypeName, StringComparison.OrdinalIgnoreCase))) - { - Type = ApiDocumentation.GetType(TypeName); - } - } - - protected override bool ShouldRender() => !string.IsNullOrEmpty(TypeName) || Type != null; + /// + /// The size of the text. + /// + [Parameter] + public Typo Typo { get; set; } = Typo.caption; protected override void BuildRenderTree(RenderTreeBuilder builder) { @@ -66,29 +87,66 @@ protected override void BuildRenderTree(RenderTreeBuilder builder) switch (TypeName) { case "System.Boolean": + builder.AddCode(0, "bool"); + break; case "System.Boolean[]": + builder.AddCode(0, "bool[]"); + break; case "System.Int32": + builder.AddCode(0, "int"); + break; case "System.Int32[]": + builder.AddCode(0, "int[]"); + break; case "System.Int64": + builder.AddCode(0, "long"); + break; case "System.Int64[]": + builder.AddCode(0, "long[]"); + break; case "System.String": + builder.AddCode(0, "string"); + break; case "System.String[]": + builder.AddCode(0, "string[]"); + break; case "System.Double": + builder.AddCode(0, "double"); + break; case "System.Double[]": + builder.AddCode(0, "double[]"); + break; case "System.Single": + builder.AddCode(0, "float"); + break; case "System.Single[]": + builder.AddCode(0, "float[]"); + break; case "System.Object": + builder.AddCode(0, "object"); + break; + case "System.Object[]": + builder.AddCode(0, "object[]"); + break; case "System.Void": - builder.AddCode(0, TypeFriendlyName); + builder.AddCode(0, "void"); break; default: // Is this a linkable type? if (!TypeName.Contains("[[")) { - builder.AddMudLink(0, $"https://learn.microsoft.com/dotnet/api/{TypeName}", TypeFriendlyName, "docs-link docs-code docs-code-primary", "_external"); + builder.AddMudLink(0, $"https://learn.microsoft.com/dotnet/api/{TypeName}", TypeFriendlyName, Typo, "docs-link docs-code docs-code-primary", "_external", (linkSequence, linkBuilder) => + { + linkBuilder.AddContent(linkSequence++, TypeFriendlyName); + linkBuilder.AddMudTooltip(linkSequence++, Placement.Top, $"External Link", (tooltipSequence, tooltipBuilder) => + { + tooltipBuilder.AddMudIcon(tooltipSequence++, "MudBlazor.Icons.Material.Filled.Link", Color.Default, Size.Small); + }); + }); } else { + // Fall back to the friendly name builder.AddCode(0, TypeFriendlyName); } break; diff --git a/src/MudBlazor.Docs/Components/ApiTypeTable.razor.cs b/src/MudBlazor.Docs/Components/ApiTypeTable.razor.cs index 8153cb1718a9..18c791b1330d 100644 --- a/src/MudBlazor.Docs/Components/ApiTypeTable.razor.cs +++ b/src/MudBlazor.Docs/Components/ApiTypeTable.razor.cs @@ -2,10 +2,6 @@ // MudBlazor licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; using Microsoft.AspNetCore.Components; using MudBlazor.Docs.Models; @@ -34,29 +30,14 @@ public partial class ApiTypeTable /// public string Keyword { get; set; } = ""; - /// - protected override async Task OnParametersSetAsync() - { - await base.OnParametersSetAsync(); - if (Table != null) - { - await Table.ReloadServerData(); - StateHasChanged(); - } - } - /// /// Occurs when has changed. /// /// The text to search for. - public async Task OnKeywordChanged(string keyword) + public Task OnKeywordChanged(string keyword) { Keyword = keyword; - if (Table != null) - { - await Table.ReloadServerData(); - StateHasChanged(); - } + return Table!.ReloadServerData(); } /// diff --git a/src/MudBlazor.Docs/Components/LandingPage/LandingSection.razor b/src/MudBlazor.Docs/Components/LandingPage/LandingSection.razor index c6167422a3d2..1ab77e4be52b 100644 --- a/src/MudBlazor.Docs/Components/LandingPage/LandingSection.razor +++ b/src/MudBlazor.Docs/Components/LandingPage/LandingSection.razor @@ -32,25 +32,26 @@ protected string SectionClassnames => new CssBuilder("mud-landingpage-section") - .AddClass(SectionClass) - .Build(); + .AddClass(SectionClass) + .Build(); protected string BackgroundClassnames => new CssBuilder("section-background d-flex flex-column justify-end") - .AddClass("straight", Straight) - .AddClass("skew", !Straight) - .AddClass(BackgroundClass) - .Build(); + .AddClass("straight", Straight) + .AddClass("skew", !Straight) + .AddClass(BackgroundClass) + .Build(); protected string EndBackgroundClassnames => new CssBuilder("section-background straight-end") - .AddClass(BackgroundClass) - .Build(); + .AddClass(BackgroundClass) + .Build(); protected string ContainerClassnames => new CssBuilder("section-container") - .AddClass("padding-straight", Straight) - .AddClass("padding-skew", !Straight) - .AddClass(Class) - .Build(); + .AddClass("padding-straight", Straight) + .AddClass("padding-skew", !Straight) + .AddClass(Class) + .Build(); + } diff --git a/src/MudBlazor.Docs/Components/LandingPage/MiniApp/MiniApp.razor b/src/MudBlazor.Docs/Components/LandingPage/MiniApp/MiniApp.razor index f4e176192c16..c69a79dd5262 100644 --- a/src/MudBlazor.Docs/Components/LandingPage/MiniApp/MiniApp.razor +++ b/src/MudBlazor.Docs/Components/LandingPage/MiniApp/MiniApp.razor @@ -289,8 +289,9 @@ protected string MiniDrawerClassNames => new CssBuilder("mini-drawer py-8 flex-grow-0 flex-shrink-0") - .AddClass("absolute", IsMobile) - .Build(); + .AddClass("absolute", IsMobile) + .Build(); + protected string ContentClassNames => new CssBuilder("flex-grow-1 flex-shrink-1") .AddClass("pa-5", !IsMobile) diff --git a/src/MudBlazor.Docs/Components/SectionContent.razor b/src/MudBlazor.Docs/Components/SectionContent.razor index b51fc7caaaf2..7e7bb72482bd 100644 --- a/src/MudBlazor.Docs/Components/SectionContent.razor +++ b/src/MudBlazor.Docs/Components/SectionContent.razor @@ -12,7 +12,7 @@ @if (Codes != null || ChildContent != null) {
- @if (Codes != null || ChildContent != null) + @if (Codes != null || (_hasCode && ChildContent != null)) { @if(Codes != null) diff --git a/src/MudBlazor.Docs/Components/SectionContent.razor.cs b/src/MudBlazor.Docs/Components/SectionContent.razor.cs index e0fa148f6902..07861486e024 100644 --- a/src/MudBlazor.Docs/Components/SectionContent.razor.cs +++ b/src/MudBlazor.Docs/Components/SectionContent.razor.cs @@ -62,7 +62,6 @@ public partial class SectionContent [Parameter] public string HighLight { get; set; } [Parameter] public IEnumerable Codes { get; set; } [Parameter] public RenderFragment ChildContent { get; set; } - [Parameter] public bool IsApiSection { get; set; } private bool _hasCode; diff --git a/src/MudBlazor.Docs/Extensions/RenderTreeExtensions.cs b/src/MudBlazor.Docs/Extensions/RenderTreeExtensions.cs index c5df68cb2317..c0083958c693 100644 --- a/src/MudBlazor.Docs/Extensions/RenderTreeExtensions.cs +++ b/src/MudBlazor.Docs/Extensions/RenderTreeExtensions.cs @@ -21,16 +21,24 @@ public static class RenderTreeExtensions /// /// /// - public static void AddMudText(this RenderTreeBuilder builder, int sequence, Typo typo = Typo.body1, string text = null) + public static void AddMudText(this RenderTreeBuilder builder, int sequence, Typo typo = Typo.body1, Color color = Color.Inherit, string text = null) { if (!string.IsNullOrEmpty(text)) { builder.OpenRegion(sequence); builder.OpenComponent(0); - builder.AddComponentParameter(1, "Typo", typo); - builder.AddComponentParameter(2, "ChildContent", (RenderFragment)(textContentBuilder => + if (typo != Typo.body1) // Only render Typo if not the MudText default { - textContentBuilder.AddContent(3, text); + builder.AddComponentParameter(1, "Typo", typo); + } + if (color != Color.Inherit) // Only render Color if not the MudText default + { + builder.AddComponentParameter(2, "Color", color); + } + builder.AddComponentParameter(3, "HtmlTag", "span"); + builder.AddComponentParameter(4, "ChildContent", (RenderFragment)(textContentBuilder => + { + textContentBuilder.AddContent(0, text); })); builder.CloseComponent(); builder.CloseRegion(); @@ -47,10 +55,13 @@ public static void AddMudText(this RenderTreeBuilder builder, int sequence, Typo /// public static void AddMudTooltip(this RenderTreeBuilder builder, int sequence, Placement placement = Placement.Top, string text = "", Action childContentBuilder = null) { + // Limit the tooltip to 60 characters + var truncatedText = text.Length > 60 ? string.Concat(text.AsSpan(0, 60), "...") : text; + // builder.OpenRegion(sequence); builder.OpenComponent(0); - builder.AddComponentParameter(1, "Text", text); + builder.AddComponentParameter(1, "Text", truncatedText); builder.AddComponentParameter(2, "Placement", placement); builder.AddComponentParameter(3, "ChildContent", (RenderFragment)(contentBuilder => { @@ -74,16 +85,12 @@ public static void AddMudIcon(this RenderTreeBuilder builder, int sequence, stri var parts = iconTypeName.Split('.'); var icon = parts[parts.Length - 1]; var svg = typeof(Icons).GetNestedType(parts[2])?.GetNestedType(parts[3])?.GetField(icon)?.GetValue(null); - // And pass into a - AddMudTooltip(builder, sequence, Placement.Top, iconTypeName, (childSequence, childContentBuilder) => - { - childContentBuilder.OpenComponent(childSequence++); - childContentBuilder.AddComponentParameter(childSequence++, "Color", color); - childContentBuilder.AddComponentParameter(childSequence++, "Size", size); - childContentBuilder.AddComponentParameter(childSequence++, "Icon", svg); - childContentBuilder.AddComponentParameter(childSequence++, "Style", "position:relative;top:7px;"); // Vertically center the icon - childContentBuilder.CloseComponent(); - }); + builder.OpenComponent(sequence++); + builder.AddComponentParameter(sequence++, "Color", color); + builder.AddComponentParameter(sequence++, "Size", size); + builder.AddComponentParameter(sequence++, "Icon", svg); + builder.AddComponentParameter(sequence++, "Style", "position:relative;top:7px;"); // Vertically center the icon + builder.CloseComponent(); } /// @@ -96,7 +103,7 @@ public static void AddMudIcon(this RenderTreeBuilder builder, int sequence, stri /// /// /// - public static void AddMudLink(this RenderTreeBuilder builder, int sequence, string href, string text = null, string cssClass = null, string target = null) + public static void AddMudLink(this RenderTreeBuilder builder, int sequence, string href, string text = null, Typo typo = Typo.body1, string cssClass = null, string target = null, Action childContentBuilder = null) { builder.OpenRegion(sequence); builder.OpenComponent(0); @@ -109,14 +116,28 @@ public static void AddMudLink(this RenderTreeBuilder builder, int sequence, stri { builder.AddComponentParameter(3, "Target", target); } - builder.AddComponentParameter(4, "ChildContent", (RenderFragment)(linkContentBuilder => + builder.AddComponentParameter(4, "Typo", typo); + builder.AddComponentParameter(3, "ChildContent", (RenderFragment)(contentBuilder => { - linkContentBuilder.AddContent(5, text); + if (childContentBuilder == null) + { + contentBuilder.AddContent(6, text); + } + else + { + childContentBuilder(sequence, contentBuilder); + } })); builder.CloseComponent(); builder.CloseRegion(); } + /// + /// Adds a code block. + /// + /// + /// + /// public static void AddCode(this RenderTreeBuilder builder, int sequence, string code) { builder.OpenRegion(sequence); @@ -134,25 +155,25 @@ public static void AddCode(this RenderTreeBuilder builder, int sequence, string /// The ordinal of this item relative to the other components. /// The type to link. /// When true, a tooltip will display with the type's summary. - public static void AddDocumentedTypeLink(this RenderTreeBuilder builder, int sequence, DocumentedType type, bool showTooltip = true) + public static void AddDocumentedTypeLink(this RenderTreeBuilder builder, int sequence, DocumentedType type, Typo typo = Typo.body1, bool showTooltip = true) { // Is a summary available? if (!string.IsNullOrEmpty(type.Summary) && showTooltip) { // - builder.AddMudTooltip(sequence, Placement.Top, type.SummaryPlain, ((childSequence, childContentBuilder) => + builder.AddMudTooltip(sequence, Placement.Top, type.SummaryPlain, (childSequence, childContentBuilder) => { - childContentBuilder.AddMudLink(childSequence++, type.ApiUrl, type.NameFriendly, "docs-link docs-code docs-code-primary"); - })); + childContentBuilder.AddMudLink(childSequence++, type.ApiUrl, type.NameFriendly, typo, "docs-link docs-code docs-code-primary"); + }); } else { // - builder.AddMudLink(sequence, type.ApiUrl, type.NameFriendly, "docs-link docs-code docs-code-primary"); + builder.AddMudLink(sequence, type.ApiUrl, type.NameFriendly, typo, "docs-link docs-code docs-code-primary"); } } - public static void AddDocumentedMemberLink(this RenderTreeBuilder builder, int sequence, DocumentedMember member) + public static void AddDocumentedMemberLink(this RenderTreeBuilder builder, int sequence, DocumentedMember member, Typo typo = Typo.body1) { // Is a summary available? if (!string.IsNullOrEmpty(member.Summary)) @@ -160,13 +181,13 @@ public static void AddDocumentedMemberLink(this RenderTreeBuilder builder, int s // builder.AddMudTooltip(sequence, Placement.Top, member.SummaryPlain, (childSequence, childContentBuilder) => { - childContentBuilder.AddMudLink(childSequence++, member.DeclaringType?.ApiUrl + "#" + member.Name, member.Name, "docs-link docs-code docs-code-primary"); + childContentBuilder.AddMudLink(childSequence++, member.DeclaringType?.ApiUrl + "#" + member.Name, member.Name, typo, "docs-link docs-code docs-code-primary"); }); } else { // - builder.AddMudLink(sequence, member.DeclaringType?.ApiUrl, member.Name, "docs-link docs-code docs-code-primary"); + builder.AddMudLink(sequence, member.DeclaringType?.ApiUrl, member.Name, typo, "docs-link docs-code docs-code-primary"); } } } diff --git a/src/MudBlazor.Docs/Models/Generated/ApiDocumentation.cs b/src/MudBlazor.Docs/Models/Generated/ApiDocumentation.cs index b6811ba26ad4..1d58c41b028f 100644 --- a/src/MudBlazor.Docs/Models/Generated/ApiDocumentation.cs +++ b/src/MudBlazor.Docs/Models/Generated/ApiDocumentation.cs @@ -2,10 +2,6 @@ // MudBlazor 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; - namespace MudBlazor.Docs.Models; /// @@ -31,7 +27,7 @@ public static partial class ApiDocumentation /// /// The generated documentation for properties. /// - public static Dictionary Properties { get; private set; } = []; + public static Dictionary Properties { get; private set; } /// /// The generated documentation for methods. @@ -45,10 +41,20 @@ public static partial class ApiDocumentation /// public static DocumentedMember GetMember(string name) { + // Is this an external member? + if (!name.StartsWith("MudBlazor", StringComparison.OrdinalIgnoreCase)) + { + return null; + } + // Is this an icon? (We don't document those, but we show them as icons) + if (name.StartsWith("MudBlazor.Icons", StringComparison.OrdinalIgnoreCase)) + { + return null; + } DocumentedMember result = GetProperty(name); result ??= GetField(name); - result ??= GetMethod(name); result ??= GetEvent(name); + result ??= GetMethod(name); return result; } @@ -63,27 +69,38 @@ public static DocumentedType GetType(string name) { return null; } + + // Is this an external member? + if (name.StartsWith("System", StringComparison.OrdinalIgnoreCase) || name.StartsWith("Microsoft", StringComparison.OrdinalIgnoreCase)) + { + return null; + } + // First, try an exact match if (Types.TryGetValue(name, out var match)) { return match; } + // Next, try with the MudBlazor namespace if (Types.TryGetValue("MudBlazor." + name, out match)) { return match; } + // Look for legacy links like "api/bar" if (LegacyToModernTypeNames.TryGetValue(name.ToLowerInvariant(), out var newTypeName) && Types.TryGetValue(newTypeName, out match)) { return match; } + // Try to match just on the name var looseMatch = Types.FirstOrDefault(type => type.Value.Name.Equals(name, StringComparison.OrdinalIgnoreCase) || type.Value.NameFriendly.Equals(name, StringComparison.OrdinalIgnoreCase)).Value; if (looseMatch != null) { return looseMatch; } + // Nothing found return null; } diff --git a/src/MudBlazor.Docs/Models/Generated/DocumentedEvent.cs b/src/MudBlazor.Docs/Models/Generated/DocumentedEvent.cs index 6ded710ba6a0..5f1271c8c5c4 100644 --- a/src/MudBlazor.Docs/Models/Generated/DocumentedEvent.cs +++ b/src/MudBlazor.Docs/Models/Generated/DocumentedEvent.cs @@ -2,17 +2,26 @@ // MudBlazor 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; -using System.Threading.Tasks; - namespace MudBlazor.Docs.Models; /// /// Represents a documented event. /// -public class DocumentedEvent : DocumentedMember +public sealed class DocumentedEvent : DocumentedMember { + /// + /// Whether this property is a parameter. + /// + /// + /// When true, the is applied to this property. + /// + public bool IsParameter { get; init; } + + /// + /// The property which triggers this event. + /// + /// + /// When set, this event enables binding for a property via @bind-[Property] in Razor. + /// + public DocumentedProperty Property { get; set; } } diff --git a/src/MudBlazor.Docs/Models/Generated/DocumentedField.cs b/src/MudBlazor.Docs/Models/Generated/DocumentedField.cs index fae092a07fee..7b5f585db54f 100644 --- a/src/MudBlazor.Docs/Models/Generated/DocumentedField.cs +++ b/src/MudBlazor.Docs/Models/Generated/DocumentedField.cs @@ -2,15 +2,11 @@ // MudBlazor licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; -using System.Diagnostics; - namespace MudBlazor.Docs.Models; /// /// Represents a documented field. /// -[DebuggerDisplay("({TypeName}) {Name}: {Summary}")] public sealed class DocumentedField : DocumentedMember { } diff --git a/src/MudBlazor.Docs/Models/Generated/DocumentedMember.cs b/src/MudBlazor.Docs/Models/Generated/DocumentedMember.cs index 6ed08de26ace..3258e7ffc7e2 100644 --- a/src/MudBlazor.Docs/Models/Generated/DocumentedMember.cs +++ b/src/MudBlazor.Docs/Models/Generated/DocumentedMember.cs @@ -22,62 +22,46 @@ public abstract class DocumentedMember /// /// This value comes from the applied to the member. /// - public string Category { get; set; } = "General"; + public string Category { get; init; } = "General"; /// /// The type which defines this member. /// - public string? DeclaringTypeName { get; set; } + public DocumentedType? DeclaringType { get; set; } /// - /// The declaring type for this member. + /// The name of the type which defines this member. /// - public DocumentedType? DeclaringType - { - get - { - if (string.IsNullOrEmpty(DeclaringTypeName)) - { - return null; - } - var key = DeclaringTypeName; - var genericsStart = DeclaringTypeName.IndexOf('['); - if (genericsStart != -1) - { - key = DeclaringTypeName.Substring(0, genericsStart); - } - if (ApiDocumentation.Types.TryGetValue(key, out var type)) - { - return type; - } - return null; - } - } + /// + /// When is not set, the name of the declaring type. This should only be set for + /// external types such as . + /// + public string? DeclaringTypeName { get; set; } /// /// Whether this member is only visible to inheritors. /// - public bool IsProtected { get; set; } + public bool IsProtected { get; init; } /// /// The name of this member. /// - public string Name { get; set; } = ""; + public string Name { get; init; } = ""; /// /// The order of this member relative to other members. /// - public int? Order { get; set; } + public int Order { get; init; } = int.MaxValue; /// /// The detailed description for this member, and any related information. /// - public string? Remarks { get; set; } + public string? Remarks { get; init; } /// /// The brief summary of this member. /// - public string? Summary { get; set; } + public string? Summary { get; init; } /// /// The brief summary of this member as plain text. @@ -87,7 +71,7 @@ public DocumentedType? DeclaringType /// /// The name of the type of this member. /// - public string TypeName { get; set; } = ""; + public string TypeName { get; init; } = ""; /// /// The type of this member. @@ -97,7 +81,7 @@ public DocumentedType? DeclaringType /// /// The user-facing name of this member's type. /// - public string? TypeFriendlyName { get; set; } + public string? TypeFriendlyName { get; init; } /// /// Extracts a plaintext version of XML documentation text. diff --git a/src/MudBlazor.Docs/Models/Generated/DocumentedMethod.cs b/src/MudBlazor.Docs/Models/Generated/DocumentedMethod.cs index b6f4e1848929..8e4d06a6966d 100644 --- a/src/MudBlazor.Docs/Models/Generated/DocumentedMethod.cs +++ b/src/MudBlazor.Docs/Models/Generated/DocumentedMethod.cs @@ -2,8 +2,6 @@ // MudBlazor licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System.Collections.Generic; - namespace MudBlazor.Docs.Models; #nullable enable @@ -11,15 +9,15 @@ namespace MudBlazor.Docs.Models; /// /// Represents documentation for a method. /// -public class DocumentedMethod : DocumentedMember +public sealed class DocumentedMethod : DocumentedMember { /// /// The parameters for this method. /// - public Dictionary Parameters { get; set; } = []; + public List Parameters { get; set; } = []; /// /// The XML documentation for what this method returns. /// - public string? Returns { get; set; } + public string Returns { get; init; } = ""; } diff --git a/src/MudBlazor.Docs/Models/Generated/DocumentedParameter.cs b/src/MudBlazor.Docs/Models/Generated/DocumentedParameter.cs index 8314b9d74dbc..58a00fa31023 100644 --- a/src/MudBlazor.Docs/Models/Generated/DocumentedParameter.cs +++ b/src/MudBlazor.Docs/Models/Generated/DocumentedParameter.cs @@ -2,18 +2,37 @@ // MudBlazor licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; - namespace MudBlazor.Docs.Models; +#nullable enable + /// /// Represents a documented parameter for a method. /// public sealed class DocumentedParameter { - public string Name { get; set; } - public Type Type { get; set; } - public string TypeFullName { get; set; } - public string TypeName { get; set; } - public string Summary { get; set; } + /// + /// The name of this parameter. + /// + public string Name { get; init; } = ""; + + /// + /// The name of the type of this member. + /// + public string TypeName { get; init; } = ""; + + /// + /// The user-facing name of this member's type. + /// + public string TypeFriendlyName { get; init; } = ""; + + /// + /// The type of this member. + /// + public DocumentedType Type => ApiDocumentation.GetType(TypeName); + + /// + /// The XML documentation for this parameter. + /// + public string Summary { get; init; } = ""; } diff --git a/src/MudBlazor.Docs/Models/Generated/DocumentedProperty.cs b/src/MudBlazor.Docs/Models/Generated/DocumentedProperty.cs index 527f55410f4c..53a9644c7a53 100644 --- a/src/MudBlazor.Docs/Models/Generated/DocumentedProperty.cs +++ b/src/MudBlazor.Docs/Models/Generated/DocumentedProperty.cs @@ -19,5 +19,13 @@ public sealed class DocumentedProperty : DocumentedMember /// /// When true, the is applied to this property. /// - public bool IsParameter { get; set; } + public bool IsParameter { get; init; } + + /// + /// The called when this property changes. + /// + /// + /// When set, this property can be bound via @bind-[Property] in Razor. + /// + public DocumentedEvent? ChangeEvent { get; set; } } diff --git a/src/MudBlazor.Docs/Models/Generated/DocumentedType.cs b/src/MudBlazor.Docs/Models/Generated/DocumentedType.cs index 8268362dda92..96d33e39206f 100644 --- a/src/MudBlazor.Docs/Models/Generated/DocumentedType.cs +++ b/src/MudBlazor.Docs/Models/Generated/DocumentedType.cs @@ -2,10 +2,7 @@ // MudBlazor 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; -using System.Linq; namespace MudBlazor.Docs.Models; @@ -15,17 +12,17 @@ namespace MudBlazor.Docs.Models; /// Represents documentation for a type. /// [DebuggerDisplay("{Name}: Summary={Summary}")] -public class DocumentedType : IComparable +public sealed class DocumentedType { /// /// The Reflection name of this type. /// - public string Name { get; set; } = ""; + public string Name { get; init; } = ""; /// /// The user-facing name of this type. /// - public string NameFriendly { get; set; } = ""; + public string NameFriendly { get; init; } = ""; /// /// The relative URL to this type's documentation. @@ -35,17 +32,17 @@ public class DocumentedType : IComparable /// /// The link to examples related to this type. /// - public string? ComponentUrl => "/components/" + Name; + public string ComponentUrl => "/components/" + Name; /// /// Whether this type is a Blazor component. /// - public bool IsComponent { get; set; } + public bool IsComponent { get; init; } /// /// The detailed description for this member, and any related information. /// - public string? Summary { get; set; } + public string Summary { get; init; } = ""; /// /// The brief summary of this member as plain text. @@ -55,17 +52,17 @@ public class DocumentedType : IComparable /// /// The brief summary of this member. /// - public string? Remarks { get; set; } + public string Remarks { get; init; } = ""; /// /// The Reflection name of this type's base type. /// - public string? BaseTypeName { get; set; } + public string BaseTypeName { get; init; } = ""; /// - /// The documentation for the base class. + /// The type this type inherits from. /// - public DocumentedType BaseType => ApiDocumentation.GetType(BaseTypeName); + public DocumentedType? BaseType => ApiDocumentation.GetType(BaseTypeName); /// /// The documented types inheriting from this class. @@ -75,34 +72,25 @@ public class DocumentedType : IComparable /// /// The properties in this type (including inherited properties). /// - public Dictionary Properties { get; set; } = []; + public Dictionary Properties { get; init; } = []; /// /// The methods in this type (including inherited methods). /// - public Dictionary Methods { get; set; } = []; + public Dictionary Methods { get; init; } = []; /// /// The fields in this type (including inherited fields). /// - public Dictionary Fields { get; set; } = []; + public Dictionary Fields { get; init; } = []; /// /// The events in this type. /// - public Dictionary Events { get; set; } = []; + public Dictionary Events { get; init; } = []; /// /// The properties in this type (including inherited properties). /// - public Dictionary GlobalSettings { get; set; } = []; - - public int CompareTo(DocumentedType? other) - { - if (other == null) - { - return -1; - } - return Name.CompareTo(other.Name); - } + public Dictionary GlobalSettings { get; init; } = []; } diff --git a/src/MudBlazor.Docs/Models/MudComponent.cs b/src/MudBlazor.Docs/Models/MudComponent.cs index 15d57f61f9bd..a0459a079dc6 100644 --- a/src/MudBlazor.Docs/Models/MudComponent.cs +++ b/src/MudBlazor.Docs/Models/MudComponent.cs @@ -1,8 +1,10 @@ using System; using System.Collections.Generic; +using System.Diagnostics; namespace MudBlazor.Docs.Models { + [DebuggerDisplay("{ComponentName}: {Name}")] public class MudComponent { public string Name { get; set; } diff --git a/src/MudBlazor.Docs/Pages/Api/Api.razor b/src/MudBlazor.Docs/Pages/Api/Api.razor index 4be7ccb9421c..ff8d1c4417c6 100644 --- a/src/MudBlazor.Docs/Pages/Api/Api.razor +++ b/src/MudBlazor.Docs/Pages/Api/Api.razor @@ -12,13 +12,14 @@ @if (DocumentedType.Summary != null) { - + } @if (DocumentedType.IsComponent) { - For examples and details on the usage of this component, visit the example page: @DocumentedType.NameFriendly + For examples and details on the usage of this component, visit the example page:
+ @(ComponentName ?? DocumentedType.NameFriendly)
} @@ -29,7 +30,7 @@ - + @@ -43,7 +44,7 @@ - + @@ -57,7 +58,7 @@ - + @@ -71,7 +72,7 @@ - + @@ -81,11 +82,11 @@ @if (DocumentedType.Events.Count > 0) { - + - + @@ -118,7 +119,7 @@ - } + } } else diff --git a/src/MudBlazor.Docs/Pages/Api/Api.razor.cs b/src/MudBlazor.Docs/Pages/Api/Api.razor.cs index e6512b64ac57..ec8dfddd8b8f 100644 --- a/src/MudBlazor.Docs/Pages/Api/Api.razor.cs +++ b/src/MudBlazor.Docs/Pages/Api/Api.razor.cs @@ -4,6 +4,7 @@ using Microsoft.AspNetCore.Components; using MudBlazor.Docs.Models; +using MudBlazor.Docs.Services; namespace MudBlazor.Docs.Pages.Api; @@ -14,12 +15,27 @@ namespace MudBlazor.Docs.Pages.Api; ///
public partial class Api { + /// + /// The service for managing menus. + /// + [Inject] + public IMenuService? MenuService { get; set; } + /// /// The name of the type to display. /// [Parameter] public string? TypeName { get; set; } + /// + /// The name of the component associated with this type. + /// + /// + /// The friendly name for the type, if it is a MudBlazor component. For example: the type + /// StackedBar will return Stacked Bar Chart. + /// + public string? ComponentName { get; set; } + /// /// The name at the top of the page. /// @@ -28,7 +44,7 @@ public partial class Api /// /// Shows the inheritance hierarchy. /// - public static bool ShowInheritance => false; + public static bool ShowInheritance => true; /// /// The type being displayed. @@ -40,7 +56,12 @@ protected override void OnParametersSet() if (DocumentedType == null || DocumentedType.Name != TypeName) { DocumentedType = ApiDocumentation.GetType(TypeName); - if (DocumentedType.IsComponent) + ComponentName = MenuService!.GetComponentName(TypeName!) ?? DocumentedType?.NameFriendly; + if (DocumentedType == null) + { + Title = TypeName + " Not Found"; + } + else if (DocumentedType.IsComponent) { Title = DocumentedType.NameFriendly + " Component"; } @@ -52,6 +73,7 @@ protected override void OnParametersSet() { Title = DocumentedType.NameFriendly + " Class"; } + } } } diff --git a/src/MudBlazor.Docs/Pages/Components/AppBar/AppBarPage.razor b/src/MudBlazor.Docs/Pages/Components/AppBar/AppBarPage.razor index 2a5debbc68e9..77c83a26afb0 100644 --- a/src/MudBlazor.Docs/Pages/Components/AppBar/AppBarPage.razor +++ b/src/MudBlazor.Docs/Pages/Components/AppBar/AppBarPage.razor @@ -43,5 +43,17 @@ + + + + + You can attach MudMenu's to the appbar, allowing for a myriad of appbar options. + + + + + + + diff --git a/src/MudBlazor.Docs/Pages/Components/AppBar/Examples/AppBarMenuExample.razor b/src/MudBlazor.Docs/Pages/Components/AppBar/Examples/AppBarMenuExample.razor new file mode 100644 index 000000000000..789fff7ad3e4 --- /dev/null +++ b/src/MudBlazor.Docs/Pages/Components/AppBar/Examples/AppBarMenuExample.razor @@ -0,0 +1,53 @@ +@namespace MudBlazor.Docs.Examples + + + + + + + + + + + Settings + + + + + + + Dark Theme + + + + + + + + + Sign In + + + + Sign Out + + + + + + + +@code { + +} diff --git a/src/MudBlazor.Docs/Pages/Components/Autocomplete/Examples/AutocompleteUsageExample.razor b/src/MudBlazor.Docs/Pages/Components/Autocomplete/Examples/AutocompleteUsageExample.razor index 6362d5034112..e723c96029a5 100644 --- a/src/MudBlazor.Docs/Pages/Components/Autocomplete/Examples/AutocompleteUsageExample.razor +++ b/src/MudBlazor.Docs/Pages/Components/Autocomplete/Examples/AutocompleteUsageExample.razor @@ -5,12 +5,12 @@ + CoerceText="@coerceText" CoerceValue="@coerceValue" SelectValueOnTab="@selectedOnTab" /> @@ -22,6 +22,8 @@ Reset Value on empty Text Coerce Text to Value Coerce Value to Text (if not found) + Select Value On Tab Key Press + @@ -29,6 +31,7 @@ private bool resetValueOnEmptyText; private bool coerceText; private bool coerceValue; + private bool selectedOnTab; private string value1, value2; private string[] states = { diff --git a/src/MudBlazor.Docs/Pages/Components/Dialog/Examples/DialogKeyboardNavigationExample_Dialog.razor b/src/MudBlazor.Docs/Pages/Components/Dialog/Examples/DialogKeyboardNavigationExample_Dialog.razor index 9ff2895f649d..1d82c7f6ce02 100644 --- a/src/MudBlazor.Docs/Pages/Components/Dialog/Examples/DialogKeyboardNavigationExample_Dialog.razor +++ b/src/MudBlazor.Docs/Pages/Components/Dialog/Examples/DialogKeyboardNavigationExample_Dialog.razor @@ -3,7 +3,7 @@ Select your favourite coffee. Hit Enter to accept or Escape to cancel. - + diff --git a/src/MudBlazor.Docs/Pages/Components/Drawer/DrawerPage.razor b/src/MudBlazor.Docs/Pages/Components/Drawer/DrawerPage.razor index 59eebd083051..e25ace46b174 100644 --- a/src/MudBlazor.Docs/Pages/Components/Drawer/DrawerPage.razor +++ b/src/MudBlazor.Docs/Pages/Components/Drawer/DrawerPage.razor @@ -29,7 +29,8 @@ - Temporary Drawers can be opened temporarily above all other content until a section is selected, or until the overlay is clicked if OverlayAutoClose is set to true. + The Temporary Drawers can be opened temporarily above all other content until a section is selected, or until the overlay is clicked if OverlayAutoClose is set to true. + This drawer type is not responsive. Temporary Drawers will stay open until the Open parameter is set to false again. @@ -40,8 +41,8 @@ - Persistent Drawer is outside its container. When opened, it forces other contents to change their size. - Persistent Drawer will stay open until the Open parameter is set to false again. + The Persistent Drawer is outside its container. When opened, it forces other contents to change their size. + This drawer type is not responsive. Persistent Drawers will stay open until the Open parameter is set to false again. @@ -52,8 +53,8 @@ - Responsive Drawers behaves persistently on wider screens and temporarily on smaller ones. - Opened Drawers close automatically when the window size becomes small, and opens after the original state has been restored. + Responsive Drawers behaves persistently on wider screens and responsively on smaller ones. + Opened Responsive Drawers close automatically when the window size becomes small, and opens after the original state has been restored according to its breakpoint configuration. @@ -66,7 +67,8 @@ - Using the Mini variant, the Drawer will shrink (default 56px). It currently only has built-in style support for MudNavLinks. + The Mini variant is a variation of the Responsive Drawer. It will responsively shrink to a slim band of icons (default 56px) according do its breakpoint configuration. + Mini Drawers currently only have built-in style support for MudNavLinks. @@ -129,7 +131,7 @@ - The switching point for Responsive Drawers can be changed using the Breakpoint parameter. The default is Breakpoint.Md. + The switching point for Responsive Drawers (DrawerVariant.Mini and DrawerVariant.Responsive) can be changed using the Breakpoint parameter. The default is Breakpoint.Md. diff --git a/src/MudBlazor.Docs/Pages/Components/Image/Examples/ImagePlaygroundExample.razor b/src/MudBlazor.Docs/Pages/Components/Image/Examples/ImagePlaygroundExample.razor index b9ca515ad2de..4da3b732c3d9 100644 --- a/src/MudBlazor.Docs/Pages/Components/Image/Examples/ImagePlaygroundExample.razor +++ b/src/MudBlazor.Docs/Pages/Components/Image/Examples/ImagePlaygroundExample.razor @@ -7,7 +7,7 @@ Options - + Tractor Door Castle @@ -15,7 +15,7 @@ Pilars Sweden - + None Cover Contain diff --git a/src/MudBlazor.Docs/Pages/Components/Select/Examples/MultiSelectCustomizedExample.razor b/src/MudBlazor.Docs/Pages/Components/Select/Examples/MultiSelectCustomizedExample.razor index 8ad0fbcff0c2..d14ec930ce23 100644 --- a/src/MudBlazor.Docs/Pages/Components/Select/Examples/MultiSelectCustomizedExample.razor +++ b/src/MudBlazor.Docs/Pages/Components/Select/Examples/MultiSelectCustomizedExample.razor @@ -1,7 +1,7 @@ @namespace MudBlazor.Docs.Examples @using System.Linq - + @foreach (var state in states) { @state diff --git a/src/MudBlazor.Docs/Pages/Components/Select/Examples/SelectCustomConverterExample.razor b/src/MudBlazor.Docs/Pages/Components/Select/Examples/SelectCustomConverterExample.razor index ec41b45a2992..64020ab338eb 100644 --- a/src/MudBlazor.Docs/Pages/Components/Select/Examples/SelectCustomConverterExample.razor +++ b/src/MudBlazor.Docs/Pages/Components/Select/Examples/SelectCustomConverterExample.razor @@ -2,7 +2,7 @@ @(pizza == null ? "Nothing selected." : $"Pizza: {pizza.Name}") - + diff --git a/src/MudBlazor.Docs/Pages/Components/Select/Examples/SelectKeyboardNavigationExample.razor b/src/MudBlazor.Docs/Pages/Components/Select/Examples/SelectKeyboardNavigationExample.razor index 5929d9fc3ae4..56d1867e46ae 100644 --- a/src/MudBlazor.Docs/Pages/Components/Select/Examples/SelectKeyboardNavigationExample.razor +++ b/src/MudBlazor.Docs/Pages/Components/Select/Examples/SelectKeyboardNavigationExample.razor @@ -1,6 +1,6 @@ @namespace MudBlazor.Docs.Examples - + diff --git a/src/MudBlazor.Docs/Pages/Features/Icons/IconsPage.razor b/src/MudBlazor.Docs/Pages/Features/Icons/IconsPage.razor index 050a8d731b6a..c0d8d73a4b54 100644 --- a/src/MudBlazor.Docs/Pages/Features/Icons/IconsPage.razor +++ b/src/MudBlazor.Docs/Pages/Features/Icons/IconsPage.razor @@ -83,7 +83,7 @@ - + @@ -94,7 +94,7 @@ - + Small Medium Large diff --git a/src/MudBlazor.Docs/Services/Menu/IMenuService.cs b/src/MudBlazor.Docs/Services/Menu/IMenuService.cs index 11a018ae613f..b683e008524c 100644 --- a/src/MudBlazor.Docs/Services/Menu/IMenuService.cs +++ b/src/MudBlazor.Docs/Services/Menu/IMenuService.cs @@ -15,6 +15,13 @@ public interface IMenuService MudComponent? GetComponent(Type? type); + /// + /// Gets a component by its type name. + /// + /// The name of the type, such as MudAlert. + /// The matching component, or null if none was found. + string? GetComponentName(string typeName); + IEnumerable Features { get; } IEnumerable Customization { get; } diff --git a/src/MudBlazor.Docs/Services/Menu/MenuService.cs b/src/MudBlazor.Docs/Services/Menu/MenuService.cs index 3c0b8d1cacd4..e9bbf224661f 100644 --- a/src/MudBlazor.Docs/Services/Menu/MenuService.cs +++ b/src/MudBlazor.Docs/Services/Menu/MenuService.cs @@ -240,6 +240,30 @@ public MenuService() : _parents.GetValueOrDefault(type); } + /// + public string? GetComponentName(string typeName) + { + var cleanName = typeName.Replace("`1", "").Replace("`2", ""); + foreach (var component in _docsComponents) + { + if (component.ComponentName != null && component.ComponentName.Equals(cleanName, StringComparison.OrdinalIgnoreCase)) + { + return component.Name; + } + if (component.GroupComponents != null) + { + foreach (var groupComponent in component.GroupComponents) + { + if (groupComponent.ComponentName.Equals(cleanName, StringComparison.OrdinalIgnoreCase)) + { + return groupComponent.Name; + } + } + } + } + return null; + } + /// /// This autogenerates the Menu for the API /// diff --git a/src/MudBlazor.Docs/Shared/Appbar.razor.cs b/src/MudBlazor.Docs/Shared/Appbar.razor.cs index a419abe228c8..3deb45d13246 100644 --- a/src/MudBlazor.Docs/Shared/Appbar.razor.cs +++ b/src/MudBlazor.Docs/Shared/Appbar.razor.cs @@ -120,8 +120,13 @@ public bool IsSearchDialogOpen [Parameter] public bool DisplaySearchBar { get; set; } = true; - private async void OnSearchResult(ApiLinkServiceEntry entry) + private async void OnSearchResult(ApiLinkServiceEntry? entry) { + if (entry is null) + { + return; + } + NavigationManager.NavigateTo(entry.Link); await Task.Delay(1000); await _searchAutocomplete.ClearAsync(); diff --git a/src/MudBlazor.UnitTests.Viewer/MudBlazor.UnitTests.Viewer.csproj b/src/MudBlazor.UnitTests.Viewer/MudBlazor.UnitTests.Viewer.csproj index 87e23c4f7186..e73999d6e448 100644 --- a/src/MudBlazor.UnitTests.Viewer/MudBlazor.UnitTests.Viewer.csproj +++ b/src/MudBlazor.UnitTests.Viewer/MudBlazor.UnitTests.Viewer.csproj @@ -2,8 +2,13 @@ net8.0 + enable MudBlazor.UnitTests + + + CS8625;CS8618;CS8602;CS8621;CS8600;CS8604;CS8603;CS8601 + diff --git a/src/MudBlazor.UnitTests.Viewer/Pages/Index.razor b/src/MudBlazor.UnitTests.Viewer/Pages/Index.razor index 7110adb3dbdd..940af21bff28 100644 --- a/src/MudBlazor.UnitTests.Viewer/Pages/Index.razor +++ b/src/MudBlazor.UnitTests.Viewer/Pages/Index.razor @@ -1,133 +1,261 @@ @page "/" @using System.Reflection -@using System.Threading - - @selectedType?.Name + + + - + - @result.Name @getDescription(result) + @result.Name @GetDescription(result) - - + + - - - Test Components + + + +
+ Test Components + + + @if (_selectedType == null) + { + @("None selected") + } + else + { + @_selectedType?.Name + } + +
+ +
+ + + + + +
+ - @foreach (var type in availableComponentTypes) + @for (int index = 0; index < _availableDirectories.Length; index++) { - @type.Name + var dir = _availableDirectories[index]; + var typesInDir = _availableComponentTypes.Where(x => _typeDirectories?[x] == dir); + + if (dir is not null && (!ShouldFilter || dir.Contains(_currentSearchText, StringComparison.OrdinalIgnoreCase))) + { + + @foreach (var type in typesInDir) + { + @type.Name + } + + } }
+ +
+ + + @if (_selectedType == null) + { + @("No test selected") + } + else + { + @GetDescription(_selectedType) + } + +
- - @getDescription(selectedType) - - - @if (@selectedType == null) + + @if (_selectedType == null) { - Select a component + Select a test using the search or nav menu } else { @* Prevent double popovers! *@ - + @TestComponent() } -
@code { - bool drawerOpen = true; - bool _rightToLeft = false; - Type selectedType = null; - Type[] availableComponentTypes = new Type[0]; - MudAutocomplete autocomplete; + private const string ExpandAllIcon = """Codestin Search App"""; + private const string CollapseAllIcon = """Codestin Search App"""; + + private bool _rightToLeft; + private Type? _selectedType; + private bool _drawerOpen = true; + private bool _expandedState = true; + private bool[] _mudGroupExpanded = []; + private Type[] _availableComponentTypes = []; + private string?[] _availableDirectories = []; + private string _currentSearchText = string.Empty; + private Dictionary? _typeDirectories; + private MudAutocomplete _autocomplete = null!; - void DocsDrawerToggle() + private bool ShouldFilter => !string.IsNullOrWhiteSpace(_currentSearchText) && _currentSearchText.Length > 2; + + private void DocsDrawerToggle() => _drawerOpen = !_drawerOpen; + + private void ToggleExpanded() { - drawerOpen = !drawerOpen; + _expandedState = !_expandedState; + for (int i = 0; i < _mudGroupExpanded.Length; i++) + { + _mudGroupExpanded[i] = _expandedState; + } } protected override async Task OnInitializedAsync() { await base.OnInitializedAsync(); - availableComponentTypes = getTestComponentTypes().ToArray(); + + _availableComponentTypes = GetTestComponentTypes().ToArray(); + _availableDirectories = GetTestFolders().ToArray(); + + _mudGroupExpanded = new bool[_availableDirectories.Length]; + ToggleExpanded(); + + _typeDirectories = _availableComponentTypes.ToDictionary( + type => type, + type => type.Namespace?.Split('.').LastOrDefault() ?? string.Empty + ); } - RenderFragment TestComponent() => builder => + private RenderFragment TestComponent() => builder => { - builder.OpenComponent(0, selectedType); + if (_selectedType is null) + { + return; + } + + builder.OpenComponent(0, _selectedType); builder.CloseComponent(); }; - IEnumerable getTestComponentTypes() + private static IEnumerable GetTestComponentTypes() { - foreach (var type in typeof(Program).Assembly.GetTypes().OrderBy(x => x.Name)) + var types = typeof(Program).Assembly.GetTypes() + .Where(type => type.Name.Contains("Test")) + .Where(type => !type.Name.StartsWith("<")) + .Where(type => type.GetInterfaces().Contains(typeof(IComponent))) + .OrderBy(type => type.Name); + + foreach (var type in types) { - if (!type.Name.Contains("Test")) - continue; - if (type.Name.StartsWith("<")) - continue; - if (!type.GetInterfaces().Contains(typeof(IComponent))) - continue; yield return type; } - //foreach (var type in typeof(MudBlazor.Docs.Components.DocsPage).Assembly.GetTypes()) - //{ - // if (!type.Name.EndsWith("Example")) - // continue; - // if (type.Name.StartsWith("<")) - // continue; - // yield return type; - //} } - private string getDescription(Type type) + private IEnumerable GetTestFolders() { - if (type == null) - return ""; - var field = type.GetField("__description__", BindingFlags.Public | BindingFlags.Static | BindingFlags.GetField); - if (field == null || field.FieldType != typeof(string)) - return "This test component does not have a description. Field \"public static string __description__\" not found in this component."; - return (string)field.GetValue(null); + return _availableComponentTypes + .Select(type => type.Namespace?.Split('.').LastOrDefault()) + .Where(namespaceName => !string.IsNullOrEmpty(namespaceName)) + .Distinct() + .OrderBy(namespaceName => namespaceName); } private Task> Search(string text, CancellationToken token) { if (string.IsNullOrWhiteSpace(text)) - return Task.FromResult>(new Type[0]); + { + return Task.FromResult>(Type.EmptyTypes); + } - return Task.FromResult>( - availableComponentTypes.Where(type => type.Name.Contains(text, StringComparison.OrdinalIgnoreCase)) - ); + var components = _availableComponentTypes.Where(type => type.Name.Contains(text, StringComparison.OrdinalIgnoreCase)); + + return Task.FromResult(components); } - private async void OnSearchResult(Type entry) + private async void OnSearchResult(Type? entry) { - selectedType = entry; - await Task.Delay(1000); - await autocomplete.ClearAsync(); + if (entry is null) + { + return; + } + + _selectedType = entry; + await Task.Yield(); + await _autocomplete.ClearAsync(); + } + + private static string? GetDescription(Type? type) + { + if (type is null) + { + return string.Empty; + } + + var field = type.GetField("__description__", BindingFlags.Public | BindingFlags.Static | BindingFlags.GetField); + if (field is null || field.FieldType != typeof(string)) + { + return "This test component does not have a description. Field \"public static string __description__\" not found in this component."; + } + + return (string?)field.GetValue(null); } } \ No newline at end of file diff --git a/src/MudBlazor.UnitTests.Viewer/Program.cs b/src/MudBlazor.UnitTests.Viewer/Program.cs index 6ca1c5064042..6d5939361867 100644 --- a/src/MudBlazor.UnitTests.Viewer/Program.cs +++ b/src/MudBlazor.UnitTests.Viewer/Program.cs @@ -1,23 +1,18 @@ -using System; -using System.Net.Http; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Components.WebAssembly.Hosting; -using Microsoft.Extensions.DependencyInjection; +using Microsoft.AspNetCore.Components.WebAssembly.Hosting; using MudBlazor.Services; -namespace MudBlazor.UnitTests +namespace MudBlazor.UnitTests; + +public class Program { - public class Program + public static Task Main(string[] args) { - public static Task Main(string[] args) - { - var builder = WebAssemblyHostBuilder.CreateDefault(args); - builder.RootComponents.Add("#app"); + var builder = WebAssemblyHostBuilder.CreateDefault(args); + builder.RootComponents.Add("#app"); - builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) }); - builder.Services.AddMudServices(); + builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) }); + builder.Services.AddMudServices(); - return builder.Build().RunAsync(); - } + return builder.Build().RunAsync(); } } diff --git a/src/MudBlazor.UnitTests.Viewer/Shared/MainLayout.razor b/src/MudBlazor.UnitTests.Viewer/Shared/MainLayout.razor index aa902054e9ed..314a85b07d51 100644 --- a/src/MudBlazor.UnitTests.Viewer/Shared/MainLayout.razor +++ b/src/MudBlazor.UnitTests.Viewer/Shared/MainLayout.razor @@ -1,6 +1,6 @@ @inherits LayoutComponentBase - + @@ -8,11 +8,12 @@ @Body @code { - MudTheme customTheme = new MudTheme() + + private readonly MudTheme _customTheme = new() + { + LayoutProperties = new LayoutProperties { - LayoutProperties = new LayoutProperties() - { - DrawerWidthLeft = "350px" - } - }; + DrawerWidthLeft = "350px" + } + }; } diff --git a/src/MudBlazor.UnitTests.Viewer/TestComponents/Alert/AlertClickTest.razor b/src/MudBlazor.UnitTests.Viewer/TestComponents/Alert/AlertClickTest.razor index bb537c515cbf..1bab21670927 100644 --- a/src/MudBlazor.UnitTests.Viewer/TestComponents/Alert/AlertClickTest.razor +++ b/src/MudBlazor.UnitTests.Viewer/TestComponents/Alert/AlertClickTest.razor @@ -1,14 +1,9 @@ -@namespace MudBlazor.UnitTests.TestComponents - -The reactor type is RBMK-1000 +The reactor type is RBMK-1000 @code { public static string __description__ = "Badge test"; private int _value = 0; - private void TestClick() - { - _value = 1; - } + private void TestClick() => _value = 1; } \ No newline at end of file diff --git a/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutoCompleteContainer.razor b/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutoCompleteContainer.razor index 71d586cec0a8..e6095f880886 100644 --- a/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutoCompleteContainer.razor +++ b/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutoCompleteContainer.razor @@ -1,15 +1,17 @@ -@namespace MudBlazor.UnitTests.TestComponents -@using System.Threading - + - + @code { - [Parameter] public bool HasBeenDisposed { get; set; } - [Parameter] public EventCallback HasBeenDisposedChanged { get; set; } - private string value1 = "Alabama"; + private string _value1 = "Alabama"; - private List states = new List + [Parameter] + public bool HasBeenDisposed { get; set; } + + [Parameter] + public EventCallback HasBeenDisposedChanged { get; set; } + + private readonly List _states = new List { "Alabama", "Alaska", "American Samoa", "Arizona", "Arkansas", "California", "Colorado", "Connecticut", @@ -39,7 +41,8 @@ } if (string.IsNullOrEmpty(value)) - return states; - return states.Where(x => x.Contains(value, StringComparison.InvariantCultureIgnoreCase)); + return _states; + + return _states.Where(x => x.Contains(value, StringComparison.InvariantCultureIgnoreCase)); } } \ No newline at end of file diff --git a/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteAdornmentChange.razor b/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteAdornmentChange.razor index 2f5c52fef89e..3965b13ff0c8 100644 --- a/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteAdornmentChange.razor +++ b/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteAdornmentChange.razor @@ -1,17 +1,15 @@ -@namespace MudBlazor.UnitTests.TestComponents -@using System.Threading - + - + Change Icon @code { public static string __description__ = "The adornment icon should change after button click"; - private string value1 = "Alabama"; + private string _value1 = "Alabama"; - private string[] states = + private readonly string[] _states = { "Alabama", "Alaska", "American Samoa", "Arizona", "Arkansas", "California", "Colorado", "Connecticut", @@ -39,15 +37,13 @@ // if text is null or empty, show complete list if (string.IsNullOrEmpty(value)) - return states; - return states.Where(x => x.Contains(value, StringComparison.InvariantCultureIgnoreCase)); + return _states; + return _states.Where(x => x.Contains(value, StringComparison.InvariantCultureIgnoreCase)); } - public void ChangeIcon() { Icon = Icons.Material.Filled.AccessAlarm; StateHasChanged(); } - } diff --git a/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteChangeBoundObjectTest.razor b/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteChangeBoundObjectTest.razor index 21fd3f158b1d..7c63be25babc 100644 --- a/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteChangeBoundObjectTest.razor +++ b/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteChangeBoundObjectTest.razor @@ -1,11 +1,8 @@ -@namespace MudBlazor.UnitTests.TestComponents -@using System.Threading - - + - + Toggle Value @@ -14,14 +11,14 @@ @code { public static string __description__ = "Change Bound Object Value of Autocomplete. Should display value of new/updated bound value"; - private bool resetValueOnEmptyText = false; - private bool coerceText = true; - private bool coerceValue = true; + private readonly bool _resetValueOnEmptyText = false; + private readonly bool _coerceText = true; + private readonly bool _coerceValue = true; - private StringHolder StringHolder1 = new StringHolder() { StringValue = "Florida" }; - private StringHolder StringHolder2 = new StringHolder() { StringValue = "Georgia" }; - private StringHolder ActiveStringHolder = null; - private string[] states = + private readonly StringHolder _stringHolder1 = new StringHolder() { StringValue = "Florida" }; + private readonly StringHolder _stringHolder2 = new StringHolder() { StringValue = "Georgia" }; + private StringHolder _activeStringHolder = null!; + private readonly string[] _states = { "Alabama", "Alaska", "American Samoa", "Arizona", "Arkansas", "California", "Colorado", "Connecticut", @@ -41,12 +38,12 @@ private sealed class StringHolder { - public string StringValue { get; set; } + public string? StringValue { get; set; } } private void ToggleValue() { - ActiveStringHolder = ActiveStringHolder.Equals(StringHolder1) ? StringHolder2 : StringHolder1; + _activeStringHolder = _activeStringHolder.Equals(_stringHolder1) ? _stringHolder2 : _stringHolder1; StateHasChanged(); } @@ -58,12 +55,12 @@ // if text is null or empty, show complete list if (string.IsNullOrEmpty(value)) - return states; - return states.Where(x => x.Contains(value, StringComparison.InvariantCultureIgnoreCase)); + return _states; + return _states.Where(x => x.Contains(value, StringComparison.InvariantCultureIgnoreCase)); } protected override void OnInitialized() { - ActiveStringHolder = StringHolder1; + _activeStringHolder = _stringHolder1; } } \ No newline at end of file diff --git a/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteDisabledItemsTest.razor b/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteDisabledItemsTest.razor index 7503e9c26d3e..d623d71e7bf6 100644 --- a/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteDisabledItemsTest.razor +++ b/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteDisabledItemsTest.razor @@ -1,9 +1,6 @@ -@namespace MudBlazor.UnitTests.TestComponents -@using System.Threading + - - - + @context @@ -17,9 +14,9 @@ { public static string __description__ = "The Autocomplete should show states containing 'o' as disabled. They should not be selectable."; - string value = null; + private string? _value = null; - private string[] states = + private readonly string[] _states = { "Alabama", "Alaska", "American Samoa", "Arizona", "Arkansas", "California", "Colorado", "Connecticut", @@ -39,7 +36,7 @@ private Task> Search(string value, CancellationToken token) { - var result = string.IsNullOrEmpty(value) ? states : states.Where(x => x.Contains(value, StringComparison.InvariantCultureIgnoreCase)); + var result = string.IsNullOrEmpty(value) ? _states : _states.Where(x => x.Contains(value, StringComparison.InvariantCultureIgnoreCase)); return Task.FromResult(result); } } diff --git a/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteFocusTest.razor b/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteFocusTest.razor index e718fe67d6bd..d31bec740b7d 100644 --- a/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteFocusTest.razor +++ b/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteFocusTest.razor @@ -1,11 +1,8 @@ -@namespace MudBlazor.UnitTests.TestComponents -@using System.Threading - - + @@ -13,9 +10,9 @@ @code { public static string __description__ = "Initial value should be shown and popup should not open."; - private string value = "Alabama"; + private string _value = "Alabama"; - private readonly string[] states = + private readonly string[] _states = { "Alabama", "Alaska", "American Samoa", "Arizona", "Arkansas", "California", "Colorado", "Connecticut", @@ -31,7 +28,7 @@ // if text is null or empty, show complete list if (string.IsNullOrEmpty(value)) - return states; - return states.Where(x => x.Contains(value, StringComparison.InvariantCultureIgnoreCase)); + return _states; + return _states.Where(x => x.Contains(value, StringComparison.InvariantCultureIgnoreCase)); } } diff --git a/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteItemTemplateDisplayTest.razor b/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteItemTemplateDisplayTest.razor index c20aa1bd6d05..edac06c69db2 100644 --- a/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteItemTemplateDisplayTest.razor +++ b/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteItemTemplateDisplayTest.razor @@ -1,22 +1,19 @@ -@namespace MudBlazor.UnitTests.TestComponents -@using System.Threading - + - - - @context Disabled State - - - @context Selected State - - + + + @context Disabled State + + + @context Selected State + + @code { - - private string value1; - private string[] states = - { + private string? _value1; + private readonly string[] _states = + { "Alabama", "Alaska", "American Samoa", "Arizona", "Arkansas", "California", "Colorado", "Connecticut", "Delaware", "District of Columbia", "Federated States of Micronesia", @@ -31,16 +28,16 @@ "Rhode Island", "South Carolina", "South Dakota", "Tennessee", "Texas", "Utah", "Vermont", "Virgin Island", "Virginia", "Washington", "West Virginia", "Wisconsin", "Wyoming", - }; + }; - private async Task> Search(string value, CancellationToken token) - { - // In real life use an asynchronous function for fetching data from an api. - await Task.Delay(5); + private async Task> Search(string value, CancellationToken token) + { + // In real life use an asynchronous function for fetching data from an api. + await Task.Delay(5); - // if text is null or empty, show complete list - if (string.IsNullOrEmpty(value)) - return states; - return states.Where(x => x.Contains(value, StringComparison.InvariantCultureIgnoreCase)); - } + // if text is null or empty, show complete list + if (string.IsNullOrEmpty(value)) + return _states; + return _states.Where(x => x.Contains(value, StringComparison.InvariantCultureIgnoreCase)); + } } \ No newline at end of file diff --git a/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteListBeforeAndAfterRendersWithItemsTest.razor b/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteListBeforeAndAfterRendersWithItemsTest.razor index ce11c1b7a29f..7ad9aadb5351 100644 --- a/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteListBeforeAndAfterRendersWithItemsTest.razor +++ b/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteListBeforeAndAfterRendersWithItemsTest.razor @@ -1,8 +1,6 @@ -@namespace MudBlazor.UnitTests.TestComponents -@using System.Threading - + - + StartList_Content @@ -14,9 +12,9 @@ @code { public static string __description__ = "The BeforeItemsTemplate and AfterItemsTemplate should be rendered with items present."; - private string value1; + private string? _value1; - private string[] states = + private readonly string[] _states = { "Alabama", "Alaska", "American Samoa", "Arizona", "Arkansas", "California", "Colorado", "Connecticut", @@ -36,8 +34,7 @@ private Task> Search(string value, CancellationToken token) { - var result = string.IsNullOrEmpty(value) ? states : states.Where(x => x.Contains(value, StringComparison.InvariantCultureIgnoreCase)); + var result = string.IsNullOrEmpty(value) ? _states : _states.Where(x => x.Contains(value, StringComparison.InvariantCultureIgnoreCase)); return Task.FromResult(result); } - } \ No newline at end of file diff --git a/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteListEndRendersTest.razor b/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteListEndRendersTest.razor index a83787de716f..19cec35c546b 100644 --- a/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteListEndRendersTest.razor +++ b/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteListEndRendersTest.razor @@ -1,8 +1,6 @@ -@namespace MudBlazor.UnitTests.TestComponents -@using System.Threading - + - + EndList_Content @@ -11,9 +9,9 @@ @code { public static string __description__ = "There are no items after filtering, so the no items template should render"; - private string value1; + private string? _value1; - private string[] states = + private readonly string[] _states = { "Alabama", "Alaska", "American Samoa", "Arizona", "Arkansas", "California", "Colorado", "Connecticut", @@ -36,6 +34,6 @@ // In real life use an asynchronous function for fetching data from an api. await Task.Delay(5, token); - return states.Where(x => x.Contains("some string", StringComparison.InvariantCultureIgnoreCase)); + return _states.Where(x => x.Contains("some string", StringComparison.InvariantCultureIgnoreCase)); } } \ No newline at end of file diff --git a/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteListStartRendersTest.razor b/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteListStartRendersTest.razor index a338d44a716d..c33220463702 100644 --- a/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteListStartRendersTest.razor +++ b/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteListStartRendersTest.razor @@ -1,8 +1,6 @@ -@namespace MudBlazor.UnitTests.TestComponents -@using System.Threading - + - + StartList_Content @@ -11,9 +9,9 @@ @code { public static string __description__ = "There are no items after filtering, so the no items template should render"; - private string value1; + private string? _value1; - private string[] states = + private readonly string[] _states = { "Alabama", "Alaska", "American Samoa", "Arizona", "Arkansas", "California", "Colorado", "Connecticut", @@ -35,6 +33,6 @@ { // In real life use an asynchronous function for fetching data from an api. await Task.Delay(5, token); - return states.Where(x => x.Contains("some string", StringComparison.InvariantCultureIgnoreCase)); + return _states.Where(x => x.Contains("some string", StringComparison.InvariantCultureIgnoreCase)); } } \ No newline at end of file diff --git a/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteRequiredTest.razor b/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteRequiredTest.razor index fd34a4c4efb3..ebbe3689bf69 100644 --- a/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteRequiredTest.razor +++ b/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteRequiredTest.razor @@ -1,18 +1,15 @@ -@namespace MudBlazor.UnitTests.TestComponents -@using System.Threading + - - - + @code { public static string __description__ = "The Autocomplete should not show required-error initially. The first (empty) item should."; - string value = null; + private string? _value = null; - private string[] states = -{ + private readonly string[] _states = + { string.Empty, "Alabama", "Alaska", "American Samoa", "Arizona", "Arkansas", "California", "Colorado", "Connecticut", @@ -32,7 +29,7 @@ private Task> Search(string value, CancellationToken token) { - var result = string.IsNullOrEmpty(value) ? states : states.Where(x => x.Contains(value, StringComparison.InvariantCultureIgnoreCase)); + var result = string.IsNullOrEmpty(value) ? _states : _states.Where(x => x.Contains(value, StringComparison.InvariantCultureIgnoreCase)); return Task.FromResult(result); } } diff --git a/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteResetTest.razor b/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteResetTest.razor index b7cce846340e..a923c6f6eef4 100644 --- a/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteResetTest.razor +++ b/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteResetTest.razor @@ -1,6 +1,4 @@ -@using System.Threading -@namespace MudBlazor.UnitTests.TestComponents - + @code { -#nullable enable private MudAutocomplete _selectAsync = null!; private readonly IEnumerable _elements = new List(2) { @@ -24,14 +21,12 @@ { return; } - await SomeTask(); + + await SomeTaskAsync(); await _selectAsync.ResetAsync(); } - private Task SomeTask() - { - return Task.CompletedTask; - } + private static Task SomeTaskAsync() => Task.CompletedTask; private Task> Search(string value, CancellationToken token) { diff --git a/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteResetValueOnEmptyText.razor b/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteResetValueOnEmptyText.razor index c31393e4cf03..3e8432c30518 100644 --- a/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteResetValueOnEmptyText.razor +++ b/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteResetValueOnEmptyText.razor @@ -1,18 +1,15 @@ -@namespace MudBlazor.UnitTests.TestComponents -@using System.Threading + - - - + @code { public static string __description__ = "Initial value should be shown and popup should not open."; public int SearchCount { get; private set; } - private string value1 = "California"; + private string _value1 = "California"; - private string[] states = + private readonly string[] _states = { "Alabama", "Alaska", "American Samoa", "Arizona", "Arkansas", "California", "Colorado", "Connecticut", @@ -38,7 +35,7 @@ // if text is null or empty, show complete list if (string.IsNullOrEmpty(value)) - return states; - return states.Where(x => x.Contains(value, StringComparison.InvariantCultureIgnoreCase)); + return _states; + return _states.Where(x => x.Contains(value, StringComparison.InvariantCultureIgnoreCase)); } } diff --git a/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteSetParametersInitialization.razor b/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteSetParametersInitialization.razor index 5e856ad278a5..c42c185195f6 100644 --- a/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteSetParametersInitialization.razor +++ b/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteSetParametersInitialization.razor @@ -1,45 +1,27 @@ -@namespace MudBlazor.UnitTests.TestComponents -@using System.Threading - - @* Based on this try https://try.mudblazor.com/snippet/GacPunvDUyjdUJAh +@* Based on this try https://try.mudblazor.com/snippet/GacPunvDUyjdUJAh and this issue https://github.com/MudBlazor/MudBlazor/issues/1235*@ - + - + @code { - public ExternalList SelectedValue; + public ExternalList? SelectedValue; - private List _externalList = new(); + private List _externalList = []; - public string ToString(ExternalList el) - { - return el?.Name; - } + private static string? ToStringFunc(ExternalList? el) => el?.Name; protected override async Task OnInitializedAsync() { await Task.Delay(15); // faking http call - _externalList = new List() -{ - new ExternalList - { - Id="1", - Name="One" - }, - new ExternalList - { - Id="2", - Name="Two" - }, - new ExternalList - { - Id="3", - Name="Three" - } - }; + _externalList = + [ + new ExternalList("1", "One"), + new ExternalList("2", "Two"), + new ExternalList("3", "Three") + ]; } protected override void OnParametersSet() @@ -48,7 +30,7 @@ if (matching != null) { SelectedValue = matching; - }; + } } private async Task> Search2(string value, CancellationToken token) @@ -60,9 +42,9 @@ return _externalList.Where(x => x.Name.Contains(value, StringComparison.InvariantCultureIgnoreCase)); } - public class ExternalList + public class ExternalList(string id, string name) { - public string Id { get; set; } - public string Name { get; set; } + public string Id { get; } = id; + public string Name { get; } = name; } } \ No newline at end of file diff --git a/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteStates.razor b/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteStates.razor new file mode 100644 index 000000000000..297a583f6e27 --- /dev/null +++ b/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteStates.razor @@ -0,0 +1,46 @@ + + + + +@code { + public static string __description__ = "Autocomplete to input a US state"; + + [Parameter] + public int DebounceInterval { get; set; } + + public int SearchFuncCallCount { get; private set; } + + private string? _value1; + + private readonly string[] _states = + { + "Alabama", "Alaska", "American Samoa", "Arizona", + "Arkansas", "California", "Colorado", "Connecticut", + "Delaware", "District of Columbia", "Federated States of Micronesia", + "Florida", "Georgia", "Guam", "Hawaii", "Idaho", + "Illinois", "Indiana", "Iowa", "Kansas", "Kentucky", + "Louisiana", "Maine", "Marshall Islands", "Maryland", + "Massachusetts", "Michigan", "Minnesota", "Mississippi", + "Missouri", "Montana", "Nebraska", "Nevada", + "New Hampshire", "New Jersey", "New Mexico", "New York", + "North Carolina", "North Dakota", "Northern Mariana Islands", "Ohio", + "Oklahoma", "Oregon", "Palau", "Pennsylvania", "Puerto Rico", + "Rhode Island", "South Carolina", "South Dakota", "Tennessee", + "Texas", "Utah", "Vermont", "Virgin Island", "Virginia", + "Washington", "West Virginia", "Wisconsin", "Wyoming", + }; + + private async Task> SearchStates(string value, CancellationToken token) + { + SearchFuncCallCount++; + + // In real life use an asynchronous function for fetching data from an api. + await Task.Delay(50, token); + + // if text is null or empty, show complete list + if (string.IsNullOrEmpty(value)) + return _states; + return _states.Where(x => x.Contains(value, StringComparison.InvariantCultureIgnoreCase)); + } +} diff --git a/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteStrictFalseSelectedHighlight.razor b/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteStrictFalseSelectedHighlight.razor index 7bbfbdc90340..2320fa9e2ff5 100644 --- a/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteStrictFalseSelectedHighlight.razor +++ b/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteStrictFalseSelectedHighlight.razor @@ -1,28 +1,22 @@ -@namespace MudBlazor.UnitTests.TestComponents -@using System.Threading + - - - + @code { - public string Fruit { get; set; } + private string? _fruit; - public string[] Fruits = new string[] - { - "apple", + private readonly string[] _fruits = + [ + "apple", "banana", "pear", "carrot", "cherry", "raspberry", "peach" - }; + ]; - public Func ItemDisabledFunc = (string text) => - { - return text.Equals("carrot", StringComparison.InvariantCulture); - }; + public Func ItemDisabledFunc = text => text.Equals("carrot", StringComparison.InvariantCulture); public async Task> Search(string text, CancellationToken token) { @@ -30,9 +24,9 @@ if (string.IsNullOrWhiteSpace(text)) { - return Fruits; + return _fruits; } - return Fruits.Where(x => x.Contains(text, StringComparison.InvariantCulture)); + return _fruits.Where(x => x.Contains(text, StringComparison.InvariantCulture)); } } \ No newline at end of file diff --git a/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteStrictFalseTest.razor b/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteStrictFalseTest.razor index 9ef84465fdd7..113184c08866 100644 --- a/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteStrictFalseTest.razor +++ b/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteStrictFalseTest.razor @@ -1,58 +1,36 @@ -@namespace MudBlazor.UnitTests.TestComponents -@using System.Threading - + + Margin="Margin.Dense" ResetValueOnEmptyText="true" Strict="false" ToStringFunc="@ToStringFunc" /> + Margin="Margin.Dense" ResetValueOnEmptyText="true" Strict="false" /> @code { public static string __description__ = "Autocomplete should show the dropdown when an item is selected and the string matches ToString or ToStringFunc."; - public IEnumerable StateList { get; set; } - public State StateDetails { get; set; } - public State StateDetails2 { get; set; } + public State? StateDetails { get; set; } + public State? StateDetails2 { get; set; } public async Task> SearchStateAsync(string value, CancellationToken token) { await Task.Delay(5, token); if (string.IsNullOrEmpty(value)) - return states.Select(x => new State(x)); - return states.Where(x => x.Contains(value, StringComparison.InvariantCultureIgnoreCase)).Select(x => new State(x)); + return _states.Select(x => new State(x)); + return _states.Where(x => x.Contains(value, StringComparison.InvariantCultureIgnoreCase)).Select(x => new State(x)); } public async Task> SearchStateToStringAsync(string value, CancellationToken token) { await Task.Delay(5, token); if (string.IsNullOrEmpty(value)) - return states.Select(x => new StateToString(x)); - return states.Where(x => x.Contains(value, StringComparison.InvariantCultureIgnoreCase)).Select(x => new StateToString(x)); + return _states.Select(x => new StateToString(x)); + return _states.Where(x => x.Contains(value, StringComparison.InvariantCultureIgnoreCase)).Select(x => new StateToString(x)); } - public record StateToString : State - { - public StateToString(string stateName) : base(stateName) { } - - public override string ToString() - { - return StateName; - } - } - - public record State - { - public string StateName { get; set; } - public State(string stateName) - { - StateName = stateName; - } - } - - private string[] states = - { + private readonly string[] _states = + [ "Alabama", "Alaska", "American Samoa", "Arizona", "Arkansas", "California", "Colorado", "Connecticut", "Delaware", "District of Columbia", "Federated States of Micronesia", @@ -66,6 +44,15 @@ "Oklahoma", "Oregon", "Palau", "Pennsylvania", "Puerto Rico", "Rhode Island", "South Carolina", "South Dakota", "Tennessee", "Texas", "Utah", "Vermont", "Virgin Island", "Virginia", - "Washington", "West Virginia", "Wisconsin", "Wyoming", - }; + "Washington", "West Virginia", "Wisconsin", "Wyoming" + ]; + + private static string? ToStringFunc(State? s) => s?.StateName; + + public record StateToString(string StateName) : State(StateName) + { + public override string ToString() => StateName; + } + + public record State(string StateName); } diff --git a/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteSyncTest.razor b/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteSyncTest.razor index 63e647753a8b..de4ea1a80afe 100644 --- a/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteSyncTest.razor +++ b/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteSyncTest.razor @@ -1,7 +1,4 @@ -@namespace MudBlazor.UnitTests.TestComponents -@using System.Threading - - + @@ -10,7 +7,7 @@ public const string AutocompleteClass = "autocomplete-test"; - public static readonly string[] Items = { "One", "Two", "Three" }; + public static readonly string[] Items = ["One", "Two", "Three"]; private Task> Search(string text, CancellationToken token) { diff --git a/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteTest1.razor b/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteTest1.razor index a5a086b4c367..fd6c2a94f3bd 100644 --- a/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteTest1.razor +++ b/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteTest1.razor @@ -1,15 +1,13 @@ -@namespace MudBlazor.UnitTests.TestComponents -@using System.Threading - + - + @code { public static string __description__ = "Initial value should be shown and popup should not open."; - private string value1 = "Alabama"; + private string _value1 = "Alabama"; - private string[] states = + private readonly string[] _states = { "Alabama", "Alaska", "American Samoa", "Arizona", "Arkansas", "California", "Colorado", "Connecticut", @@ -34,7 +32,7 @@ // if text is null or empty, show complete list if (string.IsNullOrEmpty(value)) - return states; - return states.Where(x => x.Contains(value, StringComparison.InvariantCultureIgnoreCase)); + return _states; + return _states.Where(x => x.Contains(value, StringComparison.InvariantCultureIgnoreCase)); } } diff --git a/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteTest2.razor b/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteTest2.razor index 281ca322a0d6..e8da49b170ec 100644 --- a/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteTest2.razor +++ b/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteTest2.razor @@ -1,15 +1,13 @@ -@namespace MudBlazor.UnitTests.TestComponents -@using System.Threading - + - + @code { public static string __description__ = "Popup should open when 3 characters are typed and close when below."; - private string value1; + private string? _value1; - private string[] states = + private readonly string[] _states = { "Alabama", "Alaska", "American Samoa", "Arizona", "Arkansas", "California", "Colorado", "Connecticut", @@ -34,7 +32,7 @@ // if text is null or empty, show complete list if (string.IsNullOrEmpty(value)) - return states; - return states.Where(x => x.Contains(value, StringComparison.InvariantCultureIgnoreCase)); + return _states; + return _states.Where(x => x.Contains(value, StringComparison.InvariantCultureIgnoreCase)); } } \ No newline at end of file diff --git a/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteTest3.razor b/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteTest3.razor index 72d6b1a9e096..41e336e5c88c 100644 --- a/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteTest3.razor +++ b/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteTest3.razor @@ -1,71 +1,70 @@ -@namespace MudBlazor.UnitTests.TestComponents -@using System.Threading - + + ToStringFunc="@ToStringFunc" @bind-Value="@_stateDetails" Variant="Variant.Outlined" + Margin="Margin.Dense" ResetValueOnEmptyText="true" /> @code { public static string __description__ = "Autocomplete should show 'Assam'."; - public IEnumerable StateList { get; set; } - public State StateDetails { get; set; } + private IEnumerable _stateList = []; + private State? _stateDetails; protected override void OnInitialized() { LoadStates(); - StateDetails = new State(); - StateDetails.StateId = 6; - StateDetails.StateName = "Assam"; + _stateDetails = new State + { + StateId = 6, + StateName = "Assam" + }; base.OnInitialized(); } - private void LoadStates() { - State s1 = new State + var s1 = new State { StateId = 1, StateName = "Delhi" }; - State s2 = new State + var s2 = new State { StateId = 2, StateName = "Gujarat" }; - State s3 = new State + var s3 = new State { StateId = 3, StateName = "Maharashtra" }; - State s4 = new State + var s4 = new State { StateId = 4, StateName = "Kerala" }; - State s5 = new State + var s5 = new State { StateId = 5, StateName = "Tamil Nadu" }; - State s6 = new State + var s6 = new State { StateId = 6, StateName = "Assam" }; - State s7 = new State + var s7 = new State { StateId = 7, StateName = "Chhattisgarh" }; - StateList = new List { s1, s2, s3, s4, s5, s6, s7 }; + _stateList = new List { s1, s2, s3, s4, s5, s6, s7 }; } public async Task> SearchStateAsync(string value, CancellationToken token) @@ -73,15 +72,19 @@ // In real life use an asynchronous function for fetching data from an api. await Task.Delay(5, token); - IEnumerable list; - if (string.IsNullOrEmpty(value)) list = StateList; - else list = StateList.Where(e => e.StateName.Contains(value, StringComparison.InvariantCultureIgnoreCase)); + IEnumerable list = string.IsNullOrEmpty(value) + ? _stateList + : _stateList.Where(e => e.StateName.Contains(value, StringComparison.InvariantCultureIgnoreCase)); + return list; } + private static string? ToStringFunc(State? arg) => arg?.StateName; + public class State { - public int StateId { get; set; } - public string StateName { get; set; } + public required int StateId { get; init; } + + public required string StateName { get; init; } } } diff --git a/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteTest4.razor b/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteTest4.razor index 199cf12b2f2e..63479ce278ce 100644 --- a/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteTest4.razor +++ b/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteTest4.razor @@ -1,30 +1,26 @@ -@namespace MudBlazor.UnitTests.TestComponents -@using System.Threading - + + Margin="Margin.Dense" ResetValueOnEmptyText="true" /> @code { public static string __description__ = "Autocomplete should show 'Assam' even without a ToStringFunc."; - public IEnumerable StateList { get; set; } - public State StateDetails { get; set; } = new State() { StateName = "Assam"}; + public IEnumerable StateList { get; set; } = []; + public State StateDetails { get; set; } = new() { StateName = "Assam"}; public async Task> SearchStateAsync(string value, CancellationToken token) { // In real life use an asynchronous function for fetching data from an api. await Task.Delay(5, token); - return new State[0]; + return Array.Empty(); } public class State { - public string StateName { get; set; } - public override string ToString() - { - return StateName; - } + public required string StateName { get; init; } + + public override string ToString() => StateName; } } diff --git a/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteTest5.razor b/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteTest5.razor index b03edcc8c425..7aef1087b2c2 100644 --- a/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteTest5.razor +++ b/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteTest5.razor @@ -1,15 +1,13 @@ -@namespace MudBlazor.UnitTests.TestComponents -@using System.Threading - + - + @code { public static string __description__ = "Initial value should be shown and popup should not open."; - private string value1 = "Alabama"; + private string _value1 = "Alabama"; - private string[] states = + private readonly string[] _states = { "Alabama", "Alaska", "American Samoa", "Arizona", "Arkansas", "California", "Colorado", "Connecticut", @@ -34,7 +32,7 @@ // if text is null or empty, show complete list if (string.IsNullOrEmpty(value)) - return states; - return states.Where(x => x.Contains(value, StringComparison.InvariantCultureIgnoreCase)); + return _states; + return _states.Where(x => x.Contains(value, StringComparison.InvariantCultureIgnoreCase)); } } diff --git a/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteTest6.razor b/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteTest6.razor index 2eefab0aa9d8..e3c08094c1f6 100644 --- a/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteTest6.razor +++ b/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteTest6.razor @@ -1,8 +1,6 @@ -@namespace MudBlazor.UnitTests.TestComponents -@using System.Threading - + - + Not all items are shown @@ -11,9 +9,9 @@ @code { public static string __description__ = "There are more than 10 items, so the more items template should render"; - private string value1; + private string? _value1; - private string[] states = + private readonly string[] _states = { "Alabama", "Alaska", "American Samoa", "Arizona", "Arkansas", "California", "Colorado", "Connecticut", @@ -38,7 +36,7 @@ // if text is null or empty, show complete list if (string.IsNullOrEmpty(value)) - return states; - return states.Where(x => x.Contains(value, StringComparison.InvariantCultureIgnoreCase)); + return _states; + return _states.Where(x => x.Contains(value, StringComparison.InvariantCultureIgnoreCase)); } } diff --git a/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteTest7.razor b/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteTest7.razor index 1cb099db5cd4..7e2f7eb4bacb 100644 --- a/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteTest7.razor +++ b/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteTest7.razor @@ -1,8 +1,6 @@ -@namespace MudBlazor.UnitTests.TestComponents -@using System.Threading - + - + No items found, try another search @@ -11,9 +9,9 @@ @code { public static string __description__ = "There are no items after filtering, so the no items template should render"; - private string value1; + private string? _value1; - private string[] states = + private readonly string[] states = { "Alabama", "Alaska", "American Samoa", "Arizona", "Arkansas", "California", "Colorado", "Connecticut", diff --git a/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteTest8.razor b/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteTest8.razor index fb6f40daa649..107e922557df 100644 --- a/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteTest8.razor +++ b/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteTest8.razor @@ -1,12 +1,10 @@ -@namespace MudBlazor.UnitTests.TestComponents -@using System.Threading - + -@if (mustBeShown) +@if (MustBeShown) { } @code { - public bool mustBeShown = true; + public bool MustBeShown = true; public bool HasBeenDisposed; } \ No newline at end of file diff --git a/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteTestClearable.razor b/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteTestClearable.razor index 7a0eae710cd3..8fc9c303d303 100644 --- a/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteTestClearable.razor +++ b/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteTestClearable.razor @@ -1,15 +1,13 @@ -@namespace MudBlazor.UnitTests.TestComponents -@using System.Threading - + - + @code { public static string __description__ = "Initially hidden clear button should show when text is entered or item selected."; - private string value1 = string.Empty; + private string _value1 = string.Empty; - private string[] states = + private readonly string[] _states = { "Alabama", "Alaska", "American Samoa", "Arizona", "Arkansas", "California", "Colorado", "Connecticut", @@ -34,7 +32,7 @@ // if text is null or empty, show complete list if (string.IsNullOrEmpty(value)) - return states; - return states.Where(x => x.Contains(value, StringComparison.InvariantCultureIgnoreCase)); + return _states; + return _states.Where(x => x.Contains(value, StringComparison.InvariantCultureIgnoreCase)); } } diff --git a/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteTestCoersionAndBlur.razor b/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteTestCoersionAndBlur.razor new file mode 100644 index 000000000000..67dfe36af0a8 --- /dev/null +++ b/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteTestCoersionAndBlur.razor @@ -0,0 +1,39 @@ + + + + + +@code { + public static string __description__ = "Initial value should be shown and popup should not open."; + + private string _value1 = "Alabama"; + + private readonly string[] states = + { + "Alabama", "Alaska", "American Samoa", "Arizona", + "Arkansas", "California", "Colorado", "Connecticut", + "Delaware", "District of Columbia", "Federated States of Micronesia", + "Florida", "Georgia", "Guam", "Hawaii", "Idaho", + "Illinois", "Indiana", "Iowa", "Kansas", "Kentucky", + "Louisiana", "Maine", "Marshall Islands", "Maryland", + "Massachusetts", "Michigan", "Minnesota", "Mississippi", + "Missouri", "Montana", "Nebraska", "Nevada", + "New Hampshire", "New Jersey", "New Mexico", "New York", + "North Carolina", "North Dakota", "Northern Mariana Islands", "Ohio", + "Oklahoma", "Oregon", "Palau", "Pennsylvania", "Puerto Rico", + "Rhode Island", "South Carolina", "South Dakota", "Tennessee", + "Texas", "Utah", "Vermont", "Virgin Island", "Virginia", + "Washington", "West Virginia", "Wisconsin", "Wyoming", + }; + + private async Task> Search1(string value, CancellationToken token) + { + // In real life use an asynchronous function for fetching data from an api. + await Task.Delay(50, token); + + // if text is null or empty, show complete list + if (string.IsNullOrEmpty(value)) + return states; + return states.Where(x => x.Contains(value, StringComparison.InvariantCultureIgnoreCase)); + } +} diff --git a/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteValidationDataAttrTest.razor b/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteValidationDataAttrTest.razor index 53fc98eccb84..4e2d805959d1 100644 --- a/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteValidationDataAttrTest.razor +++ b/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteValidationDataAttrTest.razor @@ -1,40 +1,34 @@ @using System.ComponentModel.DataAnnotations -@using Microsoft.AspNetCore.Components.Forms -@using System.Threading -@namespace MudBlazor.UnitTests.TestComponents + - + - + @code { - #pragma warning disable CS1998 // async without await public static string __description__ = "Test use of data attributes accessible using `For` bound expression."; - class TestModel + private class TestModel { [StringLength(3, ErrorMessage = "Should not be longer than 3")] - public string Value { get; set; } + public string? Value { get; set; } } - private TestModel Model { get; set; } = new TestModel(); + private readonly TestModel _model = new TestModel(); // What does this awkward var name means ? => https://en.wikipedia.org/wiki/Metasyntactic_variable - private string[] metasyntacticVariable = - { - "Foo", "Bar", "Qux", "Quux" - }; + private readonly string[] _metasyntacticVariable = ["Foo", "Bar", "Qux", "Quux"]; - private async Task> Search(string value, CancellationToken token) + private Task> Search(string value, CancellationToken token) { // if text is null or empty, show complete list if (string.IsNullOrEmpty(value)) - return metasyntacticVariable; - return metasyntacticVariable.Where(x => x.Contains(value, StringComparison.InvariantCultureIgnoreCase)); + return Task.FromResult>(_metasyntacticVariable); + return Task.FromResult(_metasyntacticVariable.Where(x => x.Contains(value, StringComparison.InvariantCultureIgnoreCase))); } } \ No newline at end of file diff --git a/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteValidationTest.razor b/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteValidationTest.razor index 5a54a5d4f3e1..821714459dd6 100644 --- a/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteValidationTest.razor +++ b/src/MudBlazor.UnitTests.Viewer/TestComponents/Autocomplete/AutocompleteValidationTest.razor @@ -1,32 +1,26 @@ -@namespace MudBlazor.UnitTests.TestComponents -@using System.Threading - + - - + - Reset Validation + Reset Validation @code { -#pragma warning disable CS1998 // async without await public static string __description__ = "Based on a bug report. Selecting a value should not trigger the validation error message."; - MudForm form; - string value; - private string[] states = - { - "Alabama", "Alaska", "American Samoa", "Arizona" - }; + private MudForm _form = null!; + private string? _value; + private readonly string[] states = ["Alabama", "Alaska", "American Samoa", "Arizona"]; - private async Task> Search(string value, CancellationToken token) + private Task> Search(string value, CancellationToken token) { // if text is null or empty, show complete list if (string.IsNullOrEmpty(value)) - return states; - return states.Where(x => x.Contains(value, StringComparison.InvariantCultureIgnoreCase)); + return Task.FromResult>(states); + return Task.FromResult(states.Where(x => x.Contains(value, StringComparison.InvariantCultureIgnoreCase))); } } \ No newline at end of file diff --git a/src/MudBlazor.UnitTests.Viewer/TestComponents/AvatarGroup/AvatarGroupChangeMaxTest.razor b/src/MudBlazor.UnitTests.Viewer/TestComponents/AvatarGroup/AvatarGroupChangeMaxTest.razor index 8c79990aac32..821c10b664ef 100644 --- a/src/MudBlazor.UnitTests.Viewer/TestComponents/AvatarGroup/AvatarGroupChangeMaxTest.razor +++ b/src/MudBlazor.UnitTests.Viewer/TestComponents/AvatarGroup/AvatarGroupChangeMaxTest.razor @@ -1,7 +1,5 @@ -@namespace MudBlazor.UnitTests.TestComponents - -ChangeMaxMax: @max - +ChangeMaxMax: @Max + AA BB CC @@ -13,17 +11,18 @@ @code { public static string __description__ = "Clicking the button should change the max numbers of avatars."; - public int max = 3; - void ChangeMax() + public int Max { get; set; } = 3; + + private void ChangeMax() { - if (max == 7) + if (Max == 7) { - max = 0; + Max = 0; } else { - max++; + Max++; } } } \ No newline at end of file diff --git a/src/MudBlazor.UnitTests.Viewer/TestComponents/AvatarGroup/AvatarGroupMaxAvatarsTemplateTest.razor b/src/MudBlazor.UnitTests.Viewer/TestComponents/AvatarGroup/AvatarGroupMaxAvatarsTemplateTest.razor index eaf85a5b17b2..32b3e169aeee 100644 --- a/src/MudBlazor.UnitTests.Viewer/TestComponents/AvatarGroup/AvatarGroupMaxAvatarsTemplateTest.razor +++ b/src/MudBlazor.UnitTests.Viewer/TestComponents/AvatarGroup/AvatarGroupMaxAvatarsTemplateTest.razor @@ -1,6 +1,4 @@ -@namespace MudBlazor.UnitTests.TestComponents - - + AA BB diff --git a/src/MudBlazor.UnitTests.Viewer/TestComponents/AvatarGroup/AvatarGroupMaxDefaultTest.razor b/src/MudBlazor.UnitTests.Viewer/TestComponents/AvatarGroup/AvatarGroupMaxDefaultTest.razor index 4aecfda4e5a7..12bf26e12c37 100644 --- a/src/MudBlazor.UnitTests.Viewer/TestComponents/AvatarGroup/AvatarGroupMaxDefaultTest.razor +++ b/src/MudBlazor.UnitTests.Viewer/TestComponents/AvatarGroup/AvatarGroupMaxDefaultTest.razor @@ -1,6 +1,4 @@ -@namespace MudBlazor.UnitTests.TestComponents - - + AA BB CC diff --git a/src/MudBlazor.UnitTests.Viewer/TestComponents/AvatarGroup/AvatarGroupRemoveTest.razor b/src/MudBlazor.UnitTests.Viewer/TestComponents/AvatarGroup/AvatarGroupRemoveTest.razor index ce2d0204c2df..7c80d1fd6a8b 100644 --- a/src/MudBlazor.UnitTests.Viewer/TestComponents/AvatarGroup/AvatarGroupRemoveTest.razor +++ b/src/MudBlazor.UnitTests.Viewer/TestComponents/AvatarGroup/AvatarGroupRemoveTest.razor @@ -1,8 +1,6 @@ -@namespace MudBlazor.UnitTests.TestComponents - Empty - @for(var _ = 0; _ < count; _++) + @for(var _ = 0; _ < _count; _++) { } @@ -11,11 +9,11 @@ @code { public static string __description__ = "Removing avatars should update the UI *and* the avatar group instance."; - private int count = 2; + private int _count = 2; - void Empty() + private void Empty() { - count = 0; + _count = 0; StateHasChanged(); } } diff --git a/src/MudBlazor.UnitTests.Viewer/TestComponents/AvatarGroup/AvatarGroupTest.razor b/src/MudBlazor.UnitTests.Viewer/TestComponents/AvatarGroup/AvatarGroupTest.razor index 15defbb6f867..e71dccc84f83 100644 --- a/src/MudBlazor.UnitTests.Viewer/TestComponents/AvatarGroup/AvatarGroupTest.razor +++ b/src/MudBlazor.UnitTests.Viewer/TestComponents/AvatarGroup/AvatarGroupTest.razor @@ -1,6 +1,4 @@ -@namespace MudBlazor.UnitTests.TestComponents - - + AA BB CC @@ -9,4 +7,6 @@ GG -@code { public static string __description__ = "Only 4 avatars + max avatar should be shown."; } \ No newline at end of file +@code { + public static string __description__ = "Only 4 avatars + max avatar should be shown."; +} \ No newline at end of file diff --git a/src/MudBlazor.UnitTests.Viewer/TestComponents/Badge/BadgeClickTest.razor b/src/MudBlazor.UnitTests.Viewer/TestComponents/Badge/BadgeClickTest.razor index 98d305fdc58c..92bdf551962f 100644 --- a/src/MudBlazor.UnitTests.Viewer/TestComponents/Badge/BadgeClickTest.razor +++ b/src/MudBlazor.UnitTests.Viewer/TestComponents/Badge/BadgeClickTest.razor @@ -1,6 +1,4 @@ -@namespace MudBlazor.UnitTests.TestComponents - - + diff --git a/src/MudBlazor.UnitTests.Viewer/TestComponents/Button/ButtonErrorContenCaughtException.razor b/src/MudBlazor.UnitTests.Viewer/TestComponents/Button/ButtonErrorContenCaughtException.razor index 6d1700e01440..7f021242ae0c 100644 --- a/src/MudBlazor.UnitTests.Viewer/TestComponents/Button/ButtonErrorContenCaughtException.razor +++ b/src/MudBlazor.UnitTests.Viewer/TestComponents/Button/ButtonErrorContenCaughtException.razor @@ -1,4 +1,4 @@ - + MudButton @@ -17,8 +17,7 @@ @code { -#nullable enable - private ErrorBoundary? errorBoundary; + private ErrorBoundary? _errorBoundary; public async Task HandleClickAsync() { @@ -26,5 +25,5 @@ throw new Exception("Something went wrong..."); } - public void Recover() => errorBoundary?.Recover(); + public void Recover() => _errorBoundary?.Recover(); } \ No newline at end of file diff --git a/src/MudBlazor.UnitTests.Viewer/TestComponents/Button/ButtonGroupTooltipsTest.razor b/src/MudBlazor.UnitTests.Viewer/TestComponents/Button/ButtonGroupTooltipsTest.razor index 47982b14826b..ceb6e4cfa419 100644 --- a/src/MudBlazor.UnitTests.Viewer/TestComponents/Button/ButtonGroupTooltipsTest.razor +++ b/src/MudBlazor.UnitTests.Viewer/TestComponents/Button/ButtonGroupTooltipsTest.razor @@ -20,6 +20,6 @@ @code { - private bool _rightToLeft = false; + private bool _rightToLeft; public static string __description__ = "The button group rounded corners and dividers should still work when using tooltips."; } \ No newline at end of file diff --git a/src/MudBlazor.UnitTests.Viewer/TestComponents/Button/ButtonsNestedDisabledTest.razor b/src/MudBlazor.UnitTests.Viewer/TestComponents/Button/ButtonsNestedDisabledTest.razor index 211d14b17158..0cf24708d5bc 100644 --- a/src/MudBlazor.UnitTests.Viewer/TestComponents/Button/ButtonsNestedDisabledTest.razor +++ b/src/MudBlazor.UnitTests.Viewer/TestComponents/Button/ButtonsNestedDisabledTest.razor @@ -1,6 +1,4 @@ -@namespace MudBlazor.UnitTests.TestComponents - - + Button diff --git a/src/MudBlazor.UnitTests.Viewer/TestComponents/Card/CardChildContentTest.razor b/src/MudBlazor.UnitTests.Viewer/TestComponents/Card/CardChildContentTest.razor index 690ee6d91cd8..439d72672268 100644 --- a/src/MudBlazor.UnitTests.Viewer/TestComponents/Card/CardChildContentTest.razor +++ b/src/MudBlazor.UnitTests.Viewer/TestComponents/Card/CardChildContentTest.razor @@ -1,6 +1,4 @@ -@namespace MudBlazor.UnitTests.TestComponents - - + @@ -9,7 +7,6 @@ - @code { public static string __description__ = "Badge test"; diff --git a/src/MudBlazor.UnitTests.Viewer/TestComponents/Carousel/CarouselBindingTest.razor b/src/MudBlazor.UnitTests.Viewer/TestComponents/Carousel/CarouselBindingTest.razor index 0f20c61b9da0..1138f2c490dc 100644 --- a/src/MudBlazor.UnitTests.Viewer/TestComponents/Carousel/CarouselBindingTest.razor +++ b/src/MudBlazor.UnitTests.Viewer/TestComponents/Carousel/CarouselBindingTest.razor @@ -1,6 +1,4 @@ -@namespace MudBlazor.UnitTests.TestComponents - - +
@@ -10,11 +8,11 @@ @code { - private MudCarousel _carousel; - private bool _arrows = true; - private bool _delimiters = true; - private bool _autocycle = false; - private IList _source = new List() { "Item 1", "Item 2", "Item 3", "Item 4", "Item 5" }; + private MudCarousel _carousel = null!; + private readonly bool _arrows = true; + private readonly bool _delimiters = true; + private readonly bool _autocycle = false; + private readonly List _source = ["Item 1", "Item 2", "Item 3", "Item 4", "Item 5"]; public async Task AddAsync() { @@ -30,9 +28,7 @@ { _source.RemoveAt(index); await Task.Delay(1); - _carousel.MoveTo(System.Math.Max(System.Math.Min(index, _source.Count - 1), 0)); + _carousel.MoveTo(Math.Max(Math.Min(index, _source.Count - 1), 0)); } - } - } \ No newline at end of file diff --git a/src/MudBlazor.UnitTests.Viewer/TestComponents/Carousel/CarouselTest.razor b/src/MudBlazor.UnitTests.Viewer/TestComponents/Carousel/CarouselTest.razor index 9fac0e625a9e..c45c201ac64e 100644 --- a/src/MudBlazor.UnitTests.Viewer/TestComponents/Carousel/CarouselTest.razor +++ b/src/MudBlazor.UnitTests.Viewer/TestComponents/Carousel/CarouselTest.razor @@ -1,6 +1,4 @@ -@namespace MudBlazor.UnitTests.TestComponents - - +
diff --git a/src/MudBlazor.UnitTests.Viewer/TestComponents/Charts/BarChartWithSingleXAxisTest.razor b/src/MudBlazor.UnitTests.Viewer/TestComponents/Charts/BarChartWithSingleXAxisTest.razor index ebd5fb29f7e9..1a04e809fc92 100644 --- a/src/MudBlazor.UnitTests.Viewer/TestComponents/Charts/BarChartWithSingleXAxisTest.razor +++ b/src/MudBlazor.UnitTests.Viewer/TestComponents/Charts/BarChartWithSingleXAxisTest.razor @@ -7,12 +7,12 @@ private int _index = -1; //default value cannot be 0 -> first selectedindex is 0. - public List Series = new List() - { - new ChartSeries() { Name = "United States", Data = new double[] { 40} }, - new ChartSeries() { Name = "Germany", Data = new double[] { 19 } }, - new ChartSeries() { Name = "Sweden", Data = new double[] { 8 } }, - }; + public List Series = + [ + new() { Name = "United States", Data = [40] }, + new() { Name = "Germany", Data = [19] }, + new() { Name = "Sweden", Data = [8] } + ]; - public string[] XAxisLabels = { "Jan" }; + public string[] XAxisLabels = ["Jan"]; } \ No newline at end of file diff --git a/src/MudBlazor.UnitTests.Viewer/TestComponents/Charts/ChartsWithCustomColorsTest.razor b/src/MudBlazor.UnitTests.Viewer/TestComponents/Charts/ChartsWithCustomColorsTest.razor index 83c3c943b159..e70a4367f700 100644 --- a/src/MudBlazor.UnitTests.Viewer/TestComponents/Charts/ChartsWithCustomColorsTest.razor +++ b/src/MudBlazor.UnitTests.Viewer/TestComponents/Charts/ChartsWithCustomColorsTest.razor @@ -1,21 +1,21 @@  - + - + - + - + - + - + @@ -23,62 +23,64 @@ @code { public static string __description__ = "Charts with custom colors using ChartOptions."; - public double[] Data = { 50, 25, 20, 5, 16, 14, 8, 4, 2, 8, 10, 19, 8, 17, 6, 11, 19, 24, 35, 13, 20, 12 }; + public double[] Data = [50, 25, 20, 5, 16, 14, 8, 4, 2, 8, 10, 19, 8, 17, 6, 11, 19, 24, 35, 13, 20, 12]; - public string[] Labels = { "Deep Sea Blue", "Venetian Red", "Banana Yellow", "La Salle Green", "Rich Carmine", "Shiraz", "Cloud Burst", - "Neon Pink", "Ocean", "Orangey Red", "Catalina Blue", "Fountain Blue", "Irish Green", "Wild Strawberry", - "Geraldine", "Grey Teal", "Baby Pink", "Thunderbird", "Navy", "Aqua Marina", "Lavender Pinocchio", "Deep Sea Blue" + public string[] Labels = + [ + "Deep Sea Blue", "Venetian Red", "Banana Yellow", "La Salle Green", "Rich Carmine", "Shiraz", "Cloud Burst", + "Neon Pink", "Ocean", "Orangey Red", "Catalina Blue", "Fountain Blue", "Irish Green", "Wild Strawberry", + "Geraldine", "Grey Teal", "Baby Pink", "Thunderbird", "Navy", "Aqua Marina", "Lavender Pinocchio", "Deep Sea Blue" + ]; - }; + public List Series1 = + [ + new() { Name = "Deep Sea Blue", Data = [40, 20, 25, 27, 46] }, + new() { Name = "Venetian Red", Data = [19, 24, 35, 13, 28] }, + new() { Name = "Banana Yellow", Data = [8, 6, 11, 13, 4] }, + new() { Name = "La Salle Green", Data = [18, 9, 7, 10, 7] }, + new() { Name = "Rich Carmine", Data = [9, 14, 6, 15, 20] }, + new() { Name = "Shiraz", Data = [9, 4, 11, 5, 19] }, + new() { Name = "Cloud Burst", Data = [14, 9, 20, 16, 6] }, + new() { Name = "Neon Pink", Data = [14, 8, 4, 14, 8] }, + new() { Name = "Ocean", Data = [11, 20, 13, 5, 5] }, + new() { Name = "Orangey Red", Data = [6, 6, 19, 20, 6] }, + new() { Name = "Catalina Blue", Data = [3, 2, 20, 3, 10] }, + new() { Name = "Fountain Blue", Data = [3, 18, 11, 12, 3] }, + new() { Name = "Irish Green", Data = [20, 5, 15, 16, 13] }, + new() { Name = "Wild Strawberry", Data = [15, 9, 12, 12, 1] }, + new() { Name = "Geraldine", Data = [5, 13, 19, 15, 8] }, + new() { Name = "Grey Teal", Data = [12, 16, 20, 16, 17] }, + new() { Name = "Baby Pink", Data = [1, 18, 10, 19, 8] }, + new() { Name = "Thunderbird", Data = [15, 16, 10, 8, 5] }, + new() { Name = "Navy", Data = [16, 2, 3, 5, 5] }, + new() { Name = "Aqua Marina", Data = [17, 6, 11, 19, 6] }, + new() { Name = "Lavender Pinocchio", Data = [1, 11, 4, 18, 1] }, + new() { Name = "Deep Sea Blue", Data = [1, 11, 4, 18, 1] } + ]; - public List Series1 = new List() - { - new ChartSeries() { Name = "Deep Sea Blue", Data = new double[] { 40, 20, 25, 27, 46 } }, - new ChartSeries() { Name = "Venetian Red", Data = new double[] { 19, 24, 35, 13, 28 } }, - new ChartSeries() { Name = "Banana Yellow", Data = new double[] { 8, 6, 11, 13, 4 } }, - new ChartSeries() { Name = "La Salle Green", Data = new double[] { 18, 9, 7, 10, 7 } }, - new ChartSeries() { Name = "Rich Carmine", Data = new double[] { 9, 14, 6, 15, 20 } }, - new ChartSeries() { Name = "Shiraz", Data = new double[] { 9, 4, 11, 5, 19 } }, - new ChartSeries() { Name = "Cloud Burst", Data = new double[] { 14, 9, 20, 16, 6 } }, - new ChartSeries() { Name = "Neon Pink", Data = new double[] { 14, 8, 4, 14, 8 } }, - new ChartSeries() { Name = "Ocean", Data = new double[] { 11, 20, 13, 5, 5 } }, - new ChartSeries() { Name = "Orangey Red", Data = new double[] { 6, 6, 19, 20, 6 } }, - new ChartSeries() { Name = "Catalina Blue", Data = new double[] { 3, 2, 20, 3, 10 } }, - new ChartSeries() { Name = "Fountain Blue", Data = new double[] { 3, 18, 11, 12, 3 } }, - new ChartSeries() { Name = "Irish Green", Data = new double[] { 20, 5, 15, 16, 13 } }, - new ChartSeries() { Name = "Wild Strawberry", Data = new double[] { 15, 9, 12, 12, 1 } }, - new ChartSeries() { Name = "Geraldine", Data = new double[] { 5, 13, 19, 15, 8 } }, - new ChartSeries() { Name = "Grey Teal", Data = new double[] { 12, 16, 20, 16, 17 } }, - new ChartSeries() { Name = "Baby Pink", Data = new double[] { 1, 18, 10, 19, 8 } }, - new ChartSeries() { Name = "Thunderbird", Data = new double[] { 15, 16, 10, 8, 5 } }, - new ChartSeries() { Name = "Navy", Data = new double[] { 16, 2, 3, 5, 5 } }, - new ChartSeries() { Name = "Aqua Marina", Data = new double[] { 17, 6, 11, 19, 6 } }, - new ChartSeries() { Name = "Lavender Pinocchio", Data = new double[] { 1, 11, 4, 18, 1 } }, - new ChartSeries() { Name = "Deep Sea Blue", Data = new double[] { 1, 11, 4, 18, 1 } } - }; + public List Series2 = + [ + new() { Name = "Deep Sea Blue", Data = [40, 20, 25, 27, 46] }, + new() { Name = "Venetian Red", Data = [19, 24, 35, 13, 28] }, + new() { Name = "Banana Yellow", Data = [8, 6, 11, 13, 4] } + ]; - public List Series2 = new List() - { - new ChartSeries() { Name = "Deep Sea Blue", Data = new double[] { 40, 20, 25, 27, 46 } }, - new ChartSeries() { Name = "Venetian Red", Data = new double[] { 19, 24, 35, 13, 28 } }, - new ChartSeries() { Name = "Banana Yellow", Data = new double[] { 8, 6, 11, 13, 4 } }, - }; - - public string[] XAxisLabels = { "1", "2", "3", "4", "5" }; + public string[] XAxisLabels = ["1", "2", "3", "4", "5"]; - private ChartOptions Options1 = new ChartOptions() + private readonly ChartOptions _options1 = new() { - ChartPalette = new string[] { "#015482", "#CC1512", "#FFE135", "#087830", "#D70040", "#B20931", "#202E54", "#F535AA", "#017B92", - "#FA4224", "#062A78", "#56B4BE", "#207000", "#FF43A4", "#FB8989", "#5E9B8A", "#FFB7CE", "#C02B18", - "#01153E", "#2EE8BB", "#EBDDE2" - }, + ChartPalette = + [ + "#015482", "#CC1512", "#FFE135", "#087830", "#D70040", "#B20931", "#202E54", "#F535AA", "#017B92", + "#FA4224", "#062A78", "#56B4BE", "#207000", "#FF43A4", "#FB8989", "#5E9B8A", "#FFB7CE", "#C02B18", + "#01153E", "#2EE8BB", "#EBDDE2" + ], }; - private ChartOptions Options2 = new ChartOptions() + private readonly ChartOptions _options2 = new() { - ChartPalette = new string[] { "#5bdfeb" }, + ChartPalette = ["#5bdfeb"], ShowLegend = false }; - } \ No newline at end of file diff --git a/src/MudBlazor.UnitTests.Viewer/TestComponents/Charts/ChartsWithCustomGraphicsTest.razor b/src/MudBlazor.UnitTests.Viewer/TestComponents/Charts/ChartsWithCustomGraphicsTest.razor index e108a71c0d16..f61bf160fc91 100644 --- a/src/MudBlazor.UnitTests.Viewer/TestComponents/Charts/ChartsWithCustomGraphicsTest.razor +++ b/src/MudBlazor.UnitTests.Viewer/TestComponents/Charts/ChartsWithCustomGraphicsTest.razor @@ -1,6 +1,6 @@  - + Chart DONUT @@ -8,7 +8,7 @@ - + PIE @@ -42,16 +42,15 @@ @code { public static string __description__ = "Charts with custom svg graphics using a RenderFragment."; - public double[] data = { 10, 420, 20, 69 }; - public string[] labels = { "Data 1", "Data 2", "Data 3", "Data 4" }; + public double[] Data = [10, 420, 20, 69]; + public string[] Labels = ["Data 1", "Data 2", "Data 3", "Data 4"]; - public List Series = new List() - { - new ChartSeries() { Name = "United States", Data = new double[] { 40, 20, 25, 27, 46, 60, 48, 80, 15 } }, - new ChartSeries() { Name = "Germany", Data = new double[] { 19, 24, 35, 13, 28, 15, -4, 16, 31 } }, - new ChartSeries() { Name = "Sweden", Data = new double[] { 8, 6, -11, 13, 4, 16, 10, 16, 18 } }, - }; - - public string[] XAxisLabels = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep" }; + public List Series = + [ + new() { Name = "United States", Data = [40, 20, 25, 27, 46, 60, 48, 80, 15] }, + new() { Name = "Germany", Data = [19, 24, 35, 13, 28, 15, -4, 16, 31] }, + new() { Name = "Sweden", Data = [8, 6, -11, 13, 4, 16, 10, 16, 18] } + ]; + public string[] XAxisLabels = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep"]; } \ No newline at end of file diff --git a/src/MudBlazor.UnitTests.Viewer/TestComponents/Charts/LineChartSelectionTest.razor b/src/MudBlazor.UnitTests.Viewer/TestComponents/Charts/LineChartSelectionTest.razor index f0364244ba63..bd3b0091b73a 100644 --- a/src/MudBlazor.UnitTests.Viewer/TestComponents/Charts/LineChartSelectionTest.razor +++ b/src/MudBlazor.UnitTests.Viewer/TestComponents/Charts/LineChartSelectionTest.razor @@ -1,17 +1,18 @@ 
- - Selected portion of the chart: @Index + + Selected portion of the chart: @_index
@code { public static string __description__ = "Clicking the chart series or legend should update the index."; - private int Index = -1; //default value cannot be 0 -> first selectedindex is 0. + private int _index = -1; //default value cannot be 0 -> first selectedindex is 0. - public List Series = new List() - { - new ChartSeries() { Name = "Series 1", Data = new double[] { 90, 79, 72, 69, 62, 62, 55, 65, 70 } }, - new ChartSeries() { Name = "Series 2", Data = new double[] { 10, 41, 35, 51, 49, 62, 69, 91, 148 } }, - }; - public string[] XAxisLabels = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep" }; + public List Series = + [ + new() { Name = "Series 1", Data = [90, 79, 72, 69, 62, 62, 55, 65, 70] }, + new() { Name = "Series 2", Data = [10, 41, 35, 51, 49, 62, 69, 91, 148] } + ]; + + public string[] XAxisLabels = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep"]; } diff --git a/src/MudBlazor.UnitTests.Viewer/TestComponents/Charts/LineChartWithBigValuesTest.razor b/src/MudBlazor.UnitTests.Viewer/TestComponents/Charts/LineChartWithBigValuesTest.razor index b0deea7afb82..707c4075055d 100644 --- a/src/MudBlazor.UnitTests.Viewer/TestComponents/Charts/LineChartWithBigValuesTest.razor +++ b/src/MudBlazor.UnitTests.Viewer/TestComponents/Charts/LineChartWithBigValuesTest.razor @@ -1,16 +1,15 @@ 
- +
@code { public static string __description__ = "Number of horizontal tick lines should be limited to sane values."; - private int Index = -1; //default value cannot be 0 -> first selectedindex is 0. + private int _index = -1; //default value cannot be 0 -> first selectedindex is 0. - public List Series = new List() - { - new ChartSeries() { Name = "Series 1", Data = new double[] { 112368124, 114457907, 108509186, 69, 62, 62, 55, 65, 70 } } - }; - public string[] XAxisLabels = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep" }; - + public List Series = + [ + new() { Name = "Series 1", Data = [112368124, 114457907, 108509186, 69, 62, 62, 55, 65, 70] } + ]; + public string[] XAxisLabels = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep"]; } \ No newline at end of file diff --git a/src/MudBlazor.UnitTests.Viewer/TestComponents/Charts/LineChartWithZeroValuesTest.razor b/src/MudBlazor.UnitTests.Viewer/TestComponents/Charts/LineChartWithZeroValuesTest.razor index f74050eb0345..a51ffdd9935c 100644 --- a/src/MudBlazor.UnitTests.Viewer/TestComponents/Charts/LineChartWithZeroValuesTest.razor +++ b/src/MudBlazor.UnitTests.Viewer/TestComponents/Charts/LineChartWithZeroValuesTest.razor @@ -7,10 +7,10 @@ private int _index = -1; //default value cannot be 0 -> first selectedindex is 0. - public List Series = new List() - { - new ChartSeries() { Name = "Series 1", Data = new double[] { 0, 0, 0, 0, 0, 0, 0, 0, 0 } } - }; + public List Series = + [ + new() { Name = "Series 1", Data = [0, 0, 0, 0, 0, 0, 0, 0, 0] } + ]; - public string[] XAxisLabels = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep" }; + public string[] XAxisLabels = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep"]; } diff --git a/src/MudBlazor.UnitTests.Viewer/TestComponents/CheckBox/CheckBoxFormTest1.razor b/src/MudBlazor.UnitTests.Viewer/TestComponents/CheckBox/CheckBoxFormTest1.razor index 5a1690b4b709..5733c8a5cdca 100644 --- a/src/MudBlazor.UnitTests.Viewer/TestComponents/CheckBox/CheckBoxFormTest1.razor +++ b/src/MudBlazor.UnitTests.Viewer/TestComponents/CheckBox/CheckBoxFormTest1.razor @@ -1,6 +1,4 @@ -@namespace MudBlazor.UnitTests.TestComponents - - + You agree that MudBlazor is awesome diff --git a/src/MudBlazor.UnitTests.Viewer/TestComponents/CheckBox/CheckBoxTest3.razor b/src/MudBlazor.UnitTests.Viewer/TestComponents/CheckBox/CheckBoxTest3.razor index 6fa2e38f2b46..5177a254c15c 100644 --- a/src/MudBlazor.UnitTests.Viewer/TestComponents/CheckBox/CheckBoxTest3.razor +++ b/src/MudBlazor.UnitTests.Viewer/TestComponents/CheckBox/CheckBoxTest3.razor @@ -1,10 +1,8 @@ -@namespace MudBlazor.UnitTests.TestComponents - -Synced -Synced +Synced +Synced @code { public static string __description__ = "Clicking any checkbox should toggle both."; - bool is_checked = true; + private bool _isChecked = true; } diff --git a/src/MudBlazor.UnitTests.Viewer/TestComponents/CheckBox/CheckBoxTest4.razor b/src/MudBlazor.UnitTests.Viewer/TestComponents/CheckBox/CheckBoxTest4.razor index 352074ebabe7..da984f2d365f 100644 --- a/src/MudBlazor.UnitTests.Viewer/TestComponents/CheckBox/CheckBoxTest4.razor +++ b/src/MudBlazor.UnitTests.Viewer/TestComponents/CheckBox/CheckBoxTest4.razor @@ -1,6 +1,4 @@ -@namespace MudBlazor.UnitTests.TestComponents - -Dense +Dense Small Normal Large diff --git a/src/MudBlazor.UnitTests.Viewer/TestComponents/CheckBox/CheckBoxesBindAgainstArrayTest.razor b/src/MudBlazor.UnitTests.Viewer/TestComponents/CheckBox/CheckBoxesBindAgainstArrayTest.razor index a4ca47d175b6..c7073788e309 100644 --- a/src/MudBlazor.UnitTests.Viewer/TestComponents/CheckBox/CheckBoxesBindAgainstArrayTest.razor +++ b/src/MudBlazor.UnitTests.Viewer/TestComponents/CheckBox/CheckBoxesBindAgainstArrayTest.razor @@ -1,28 +1,19 @@ -@namespace MudBlazor.UnitTests.TestComponents - - - @for (int i = 0; i < amenities.Length; i++) + + @for (int i = 0; i < _amenities.Length; i++) { var local = i; - @amenities[local] + @_amenities[local] } -

@selected

+

@Selected

@code { public static string __description__ = "Binding checkboxes two-way against an array of bools"; - private string[] amenities = - { - "A", "B", "C", "D", "E" - }; - - private bool[] values = - { - true, false, true, false, true - }; - string selected => string.Join(", ", amenities.Zip(values, (a, b)=>$"{a}={b}")); + private readonly string[] _amenities = ["A", "B", "C", "D", "E"]; + private readonly bool[] _values = [true, false, true, false, true]; + private string Selected => string.Join(", ", _amenities.Zip(_values, (a, b)=>$"{a}={b}")); } diff --git a/src/MudBlazor.UnitTests.Viewer/TestComponents/Chip/ChipAvatarContentTest.razor b/src/MudBlazor.UnitTests.Viewer/TestComponents/Chip/ChipAvatarContentTest.razor index 2f01e1c1befd..86e3c8b0853c 100644 --- a/src/MudBlazor.UnitTests.Viewer/TestComponents/Chip/ChipAvatarContentTest.razor +++ b/src/MudBlazor.UnitTests.Viewer/TestComponents/Chip/ChipAvatarContentTest.razor @@ -1,6 +1,4 @@ -@namespace MudBlazor.UnitTests.TestComponents - - + JD diff --git a/src/MudBlazor.UnitTests.Viewer/TestComponents/Chip/ChipHrefCursorTest.razor b/src/MudBlazor.UnitTests.Viewer/TestComponents/Chip/ChipHrefCursorTest.razor index 3d17b5c1b08f..7b65bf3bdfae 100644 --- a/src/MudBlazor.UnitTests.Viewer/TestComponents/Chip/ChipHrefCursorTest.razor +++ b/src/MudBlazor.UnitTests.Viewer/TestComponents/Chip/ChipHrefCursorTest.razor @@ -1,6 +1,4 @@ -@namespace MudBlazor.UnitTests.TestComponents - - + @code { diff --git a/src/MudBlazor.UnitTests.Viewer/TestComponents/Chip/ChipLinkTest.razor b/src/MudBlazor.UnitTests.Viewer/TestComponents/Chip/ChipLinkTest.razor index 7fd094c4f3fe..049d407da8dc 100644 --- a/src/MudBlazor.UnitTests.Viewer/TestComponents/Chip/ChipLinkTest.razor +++ b/src/MudBlazor.UnitTests.Viewer/TestComponents/Chip/ChipLinkTest.razor @@ -1,16 +1,12 @@ -@namespace MudBlazor.UnitTests.TestComponents - - +
@_event
@code { public static string __description__ = "Chip with link"; - private string _event = ""; - private void Click() { - _event = "OnClick"; - } - - private void Close() { - _event = "OnClose"; - } + + private string _event = string.Empty; + + private void Click() => _event = "OnClick"; + + private void Close() => _event = "OnClose"; } \ No newline at end of file diff --git a/src/MudBlazor.UnitTests.Viewer/TestComponents/Chip/ChipOnClickTest.razor b/src/MudBlazor.UnitTests.Viewer/TestComponents/Chip/ChipOnClickTest.razor index 753516fd919a..9bcecc6ee6ed 100644 --- a/src/MudBlazor.UnitTests.Viewer/TestComponents/Chip/ChipOnClickTest.razor +++ b/src/MudBlazor.UnitTests.Viewer/TestComponents/Chip/ChipOnClickTest.razor @@ -1,16 +1,13 @@ -@namespace MudBlazor.UnitTests.TestComponents - - +
@_event
+ @code { public static string __description__ = "OnClick or OnClose should be displayed when clicking on the chip."; - private string _event = ""; - private void Click() { - _event = "OnClick"; - } - - private void Close() { - _event = "OnClose"; - } + + private string _event = string.Empty; + + private void Click() => _event = "OnClick"; + + private void Close() => _event = "OnClose"; } \ No newline at end of file diff --git a/src/MudBlazor.UnitTests.Viewer/TestComponents/ChipSet/ChipSetChipBindingTest.razor b/src/MudBlazor.UnitTests.Viewer/TestComponents/ChipSet/ChipSetChipBindingTest.razor index 456a9065c074..86d447700c30 100644 --- a/src/MudBlazor.UnitTests.Viewer/TestComponents/ChipSet/ChipSetChipBindingTest.razor +++ b/src/MudBlazor.UnitTests.Viewer/TestComponents/ChipSet/ChipSetChipBindingTest.razor @@ -16,7 +16,7 @@ } else { - Add ingredients to your coctail. + Add ingredients to your cocktail. }
@@ -30,9 +30,8 @@ @code { - private string[] _ingredients = ["Vodka", "Tomato Juice", "Olive", "Peppermint", "Vermouth", "Coconut Milk", "Port Wine"]; - private bool[] _included = new bool[7]; - private IReadOnlyCollection _selected; - + private readonly string[] _ingredients = ["Vodka", "Tomato Juice", "Olive", "Peppermint", "Vermouth", "Coconut Milk", "Port Wine"]; + private readonly bool[] _included = new bool[7]; + private IReadOnlyCollection? _selected; } diff --git a/src/MudBlazor.UnitTests.Viewer/TestComponents/ChipSet/ChipSetClearSelectionTest.razor b/src/MudBlazor.UnitTests.Viewer/TestComponents/ChipSet/ChipSetClearSelectionTest.razor index 010583273651..bd1c2f0c55ca 100644 --- a/src/MudBlazor.UnitTests.Viewer/TestComponents/ChipSet/ChipSetClearSelectionTest.razor +++ b/src/MudBlazor.UnitTests.Viewer/TestComponents/ChipSet/ChipSetClearSelectionTest.razor @@ -1,5 +1,3 @@ -@namespace MudBlazor.UnitTests.TestComponents - @@ -10,8 +8,7 @@ - -@if (_selected != null && _selected.Count > 0) { +@if (_selected is { Count: > 0 }) { @string.Join(", ", _selected.OrderBy(x => x)) } else { @@ -21,15 +18,9 @@ else { Set Empty @code { - private IReadOnlyCollection _selected; + private IReadOnlyCollection? _selected; - private void SetNull() - { - _selected = null; - } + private void SetNull() => _selected = null; - private void SetEmpty() - { - _selected = Array.Empty(); - } + private void SetEmpty() => _selected = Array.Empty(); } \ No newline at end of file diff --git a/src/MudBlazor.UnitTests.Viewer/TestComponents/ChipSet/ChipSetComparerTest.razor b/src/MudBlazor.UnitTests.Viewer/TestComponents/ChipSet/ChipSetComparerTest.razor index 49eedf8eb807..383bbf5b7c6e 100644 --- a/src/MudBlazor.UnitTests.Viewer/TestComponents/ChipSet/ChipSetComparerTest.razor +++ b/src/MudBlazor.UnitTests.Viewer/TestComponents/ChipSet/ChipSetComparerTest.razor @@ -1,8 +1,6 @@ -@namespace MudBlazor.UnitTests.TestComponents - - + - + @@ -20,30 +18,33 @@ @code { public static string __description__ = "The comparer should be used to compare coffee objects in chipset"; - private CoffeeComparer Comparer { get; } = new(); - - IReadOnlyCollection Selected { get; set; } = Array.Empty(); + + private readonly CoffeeComparer _comparer = new(); + private IReadOnlyCollection Selected { get; set; } = Array.Empty(); - void SelectedChanged(IEnumerable newSelected) + private void SelectedChanged(IEnumerable newSelected) { Selected = newSelected.ToHashSet(); } - void SetSelection() + private void SetSelection() { - Selected = new[] { new Coffee("lat", "Cafe Latte!"), new Coffee("esp", "Espresso!") }; + Selected = + [ + new Coffee("lat", "Cafe Latte!"), + new Coffee("esp", "Espresso!") + ]; } - class Coffee + private class Coffee(string key, string name) { - public string Key { get; set; } - public string Name { get; set; } - public Coffee(string key, string name) { Key = key; Name = name; } + public string Key { get; } = key; + public string Name { get; } = name; } - class CoffeeComparer : IEqualityComparer + private class CoffeeComparer : IEqualityComparer { - public bool Equals(Coffee a, Coffee b) => a?.Key == b?.Key; + public bool Equals(Coffee? a, Coffee? b) => a?.Key == b?.Key; public int GetHashCode(Coffee x) => HashCode.Combine(x.Key); } } diff --git a/src/MudBlazor.UnitTests.Viewer/TestComponents/ChipSet/ChipSetDefaultChipsTest.razor b/src/MudBlazor.UnitTests.Viewer/TestComponents/ChipSet/ChipSetDefaultChipsTest.razor index 33ef25a0f489..c09c41dcd12c 100644 --- a/src/MudBlazor.UnitTests.Viewer/TestComponents/ChipSet/ChipSetDefaultChipsTest.razor +++ b/src/MudBlazor.UnitTests.Viewer/TestComponents/ChipSet/ChipSetDefaultChipsTest.razor @@ -1,6 +1,4 @@ -@namespace MudBlazor.UnitTests.TestComponents - - + @@ -30,11 +28,11 @@ public SelectionMode SelectionMode { get; set; } = SelectionMode.ToggleSelection; [Parameter] - public string[] InitialValues { get; set; } + public string[]? InitialValues { get; set; } private bool _checkMark = false; - private IReadOnlyCollection _selectedValues; - private string _selectedValue; + private IReadOnlyCollection? _selectedValues; + private string? _selectedValue; protected override void OnInitialized() { diff --git a/src/MudBlazor.UnitTests.Viewer/TestComponents/ChipSet/ChipSetKeyboardNavigationTests.razor b/src/MudBlazor.UnitTests.Viewer/TestComponents/ChipSet/ChipSetKeyboardNavigationTests.razor index 2d4579857407..9eca4303bdb9 100644 --- a/src/MudBlazor.UnitTests.Viewer/TestComponents/ChipSet/ChipSetKeyboardNavigationTests.razor +++ b/src/MudBlazor.UnitTests.Viewer/TestComponents/ChipSet/ChipSetKeyboardNavigationTests.razor @@ -22,6 +22,9 @@ @code { + private readonly List _chips = []; + private IReadOnlyCollection _selectedValues = []; + [Parameter] public bool AreChipsClosable { get; set; } @@ -34,9 +37,5 @@ [Parameter] public EventCallback> OnClose { get; set; } - private readonly List _chips = []; - private IReadOnlyCollection _selectedValues = []; - - private void AddChip() - => _chips.Add($"Chip {_chips.Count + 1}"); + private void AddChip() => _chips.Add($"Chip {_chips.Count + 1}"); } \ No newline at end of file diff --git a/src/MudBlazor.UnitTests.Viewer/TestComponents/ChipSet/ChipSetLateDefaultTest.razor b/src/MudBlazor.UnitTests.Viewer/TestComponents/ChipSet/ChipSetLateDefaultTest.razor index e144eae13dae..100cff23e713 100644 --- a/src/MudBlazor.UnitTests.Viewer/TestComponents/ChipSet/ChipSetLateDefaultTest.razor +++ b/src/MudBlazor.UnitTests.Viewer/TestComponents/ChipSet/ChipSetLateDefaultTest.razor @@ -1,6 +1,4 @@ -@namespace MudBlazor.UnitTests.TestComponents - - + @if (_extraItem) { @@ -19,7 +17,8 @@ else { @code { - bool _extraItem = false; + private bool _extraItem; + private IReadOnlyCollection? _selectedValues; + public void Enable() => _extraItem = !_extraItem; - IReadOnlyCollection _selectedValues; } \ No newline at end of file diff --git a/src/MudBlazor.UnitTests.Viewer/TestComponents/ChipSet/ChipSetMultiSelectionTest.razor b/src/MudBlazor.UnitTests.Viewer/TestComponents/ChipSet/ChipSetMultiSelectionTest.razor index 4bac3be4c4a9..889e7cdf0ca4 100644 --- a/src/MudBlazor.UnitTests.Viewer/TestComponents/ChipSet/ChipSetMultiSelectionTest.razor +++ b/src/MudBlazor.UnitTests.Viewer/TestComponents/ChipSet/ChipSetMultiSelectionTest.razor @@ -1,6 +1,4 @@ -@namespace MudBlazor.UnitTests.TestComponents - - + @@ -24,11 +22,11 @@ @code { - [Parameter] - public string[] InitialValues { get; set; } + private string? _selectedValue; + private IReadOnlyCollection? _selectedValues; - private string _selectedValue; - private IReadOnlyCollection _selectedValues; + [Parameter] + public string[]? InitialValues { get; set; } protected override void OnInitialized() { diff --git a/src/MudBlazor.UnitTests.Viewer/TestComponents/ChipSet/ChipSetReadOnlyTest.razor b/src/MudBlazor.UnitTests.Viewer/TestComponents/ChipSet/ChipSetReadOnlyTest.razor index 95d783117216..59743e0a237f 100644 --- a/src/MudBlazor.UnitTests.Viewer/TestComponents/ChipSet/ChipSetReadOnlyTest.razor +++ b/src/MudBlazor.UnitTests.Viewer/TestComponents/ChipSet/ChipSetReadOnlyTest.razor @@ -1,6 +1,4 @@ -@namespace MudBlazor.UnitTests.TestComponents - - + @@ -12,7 +10,5 @@ @code { - private static void Close() { - throw new Exception("OnClose should not be possible with ReadOnly=true."); - } + private static void Close() => throw new Exception("OnClose should not be possible with ReadOnly=true."); } diff --git a/src/MudBlazor.UnitTests.Viewer/TestComponents/ChipSet/ChipSetSelectionTwoWayBindingTest.razor b/src/MudBlazor.UnitTests.Viewer/TestComponents/ChipSet/ChipSetSelectionTwoWayBindingTest.razor index 974b2cbc8e3f..1909b78de580 100644 --- a/src/MudBlazor.UnitTests.Viewer/TestComponents/ChipSet/ChipSetSelectionTwoWayBindingTest.razor +++ b/src/MudBlazor.UnitTests.Viewer/TestComponents/ChipSet/ChipSetSelectionTwoWayBindingTest.razor @@ -15,6 +15,6 @@ @code { public static string __description__ = "The chipsets should mirror their respective selections"; - IReadOnlyCollection _selectedValues = [ 1 ]; + private IReadOnlyCollection _selectedValues = [ 1 ]; } diff --git a/src/MudBlazor.UnitTests.Viewer/TestComponents/ChipSet/ChipSetSingleSelectionTest.razor b/src/MudBlazor.UnitTests.Viewer/TestComponents/ChipSet/ChipSetSingleSelectionTest.razor index a2137b65c0eb..28e55ca5a844 100644 --- a/src/MudBlazor.UnitTests.Viewer/TestComponents/ChipSet/ChipSetSingleSelectionTest.razor +++ b/src/MudBlazor.UnitTests.Viewer/TestComponents/ChipSet/ChipSetSingleSelectionTest.razor @@ -1,6 +1,4 @@ -@namespace MudBlazor.UnitTests.TestComponents - - + @@ -28,10 +26,10 @@ public SelectionMode SelectionMode { get; set; } = SelectionMode.ToggleSelection; [Parameter] - public string InitialValue { get; set; } + public string? InitialValue { get; set; } - private string _selectedValue; - private IReadOnlyCollection _selectedValues; + private string? _selectedValue; + private IReadOnlyCollection? _selectedValues; protected override void OnInitialized() { diff --git a/src/MudBlazor.UnitTests.Viewer/TestComponents/ChipSet/ChipSetTest.razor b/src/MudBlazor.UnitTests.Viewer/TestComponents/ChipSet/ChipSetTest.razor index 159169a03051..67562790bd3b 100644 --- a/src/MudBlazor.UnitTests.Viewer/TestComponents/ChipSet/ChipSetTest.razor +++ b/src/MudBlazor.UnitTests.Viewer/TestComponents/ChipSet/ChipSetTest.razor @@ -1,6 +1,4 @@ -@namespace MudBlazor.UnitTests.TestComponents - - + @@ -23,6 +21,10 @@ else { [Parameter] public bool MultiSelection { get; set; } - private bool _checkMark = false; + private bool _checkMark; private IReadOnlyCollection _selected = ["Milk", "Cornflakes"]; + + private SelectionMode GetSelectionMod() => MultiSelection + ? SelectionMode.MultiSelection + : SelectionMode.SingleSelection; } \ No newline at end of file diff --git a/src/MudBlazor.UnitTests.Viewer/TestComponents/Collapse/CollapseBindingTest.razor b/src/MudBlazor.UnitTests.Viewer/TestComponents/Collapse/CollapseBindingTest.razor index 6b4f48a9d308..fc097a218d10 100644 --- a/src/MudBlazor.UnitTests.Viewer/TestComponents/Collapse/CollapseBindingTest.razor +++ b/src/MudBlazor.UnitTests.Viewer/TestComponents/Collapse/CollapseBindingTest.razor @@ -1,6 +1,4 @@ -@namespace MudBlazor.UnitTests.TestComponents - - + @(_expanded ? "Collapse" : "Expand") diff --git a/src/MudBlazor.UnitTests.Viewer/TestComponents/ColorPicker/PickerWithFixedView.razor b/src/MudBlazor.UnitTests.Viewer/TestComponents/ColorPicker/PickerWithFixedView.razor index a5544fc284fb..36f86aeba685 100644 --- a/src/MudBlazor.UnitTests.Viewer/TestComponents/ColorPicker/PickerWithFixedView.razor +++ b/src/MudBlazor.UnitTests.Viewer/TestComponents/ColorPicker/PickerWithFixedView.razor @@ -1,9 +1,10 @@ - +@using MudBlazor.Utilities + @code { - private MudBlazor.Utilities.MudColor _colorValue; + private MudColor? _colorValue; [Parameter] public ColorPickerView ColorPickerView { get; set; } = ColorPickerView.Grid; diff --git a/src/MudBlazor.UnitTests.Viewer/TestComponents/ColorPicker/SimpleColorPickerTest.razor b/src/MudBlazor.UnitTests.Viewer/TestComponents/ColorPicker/SimpleColorPickerTest.razor index 867f75ed89bd..969657b6f6d3 100644 --- a/src/MudBlazor.UnitTests.Viewer/TestComponents/ColorPicker/SimpleColorPickerTest.razor +++ b/src/MudBlazor.UnitTests.Viewer/TestComponents/ColorPicker/SimpleColorPickerTest.razor @@ -1,10 +1,6 @@ -@namespace MudBlazor.UnitTests.TestComponents +@using MudBlazor.Utilities -@using MudBlazor.Utilities - - - - + @code { - private MudColorPicker _picker; + private MudColorPicker _picker = null!; + + public int ValueChangeCallbackCounter { get; private set; } + + [Parameter] + public MudColor ColorValue { get; set; } = "#594ae2"; + + [Parameter] + public string TextValue { get; set; } = "#594ae2"; + + [Parameter] + public IEnumerable Palette { get; set; } = ["#ff4081ff", "#2196f3ff", "#00c853ff", "#ff9800ff", "#f44336ff"]; + + [Parameter] + public ColorPickerMode ColorPickerMode { get; set; } = ColorPickerMode.RGB; + + [Parameter] + public bool ShowToolbar { get; set; } + + [Parameter] + public bool ShowColorField { get; set; } = true; + + [Parameter] + public bool ShowPreview { get; set; } = true; + + [Parameter] + public bool ShowSliders { get; set; } = true; + + [Parameter] + public bool DisableInput { get; set; } + + [Parameter] + public bool ShowModeSwitch { get; set; } = true; + + [Parameter] + public bool ShowAlpha { get; set; } = true; - public Int32 ValueChangeCallbackCounter { get; private set; } = 0; + [Parameter] + public bool DragEffect { get; set; } = true; - [Parameter] public MudColor ColorValue { get; set; } = "#594ae2"; - [Parameter] public string TextValue { get; set; } = "#594ae2"; + [Parameter] + public ColorPickerView ViewMode { get; set; } = ColorPickerView.Spectrum; - [Parameter] public IEnumerable Palette { get; set; } = new MudColor[] { "#ff4081ff", "#2196f3ff", "#00c853ff", "#ff9800ff", "#f44336ff" }; + [Parameter] + public PickerVariant Variant { get; set; } = PickerVariant.Static; - [Parameter] public ColorPickerMode ColorPickerMode { get; set; } = ColorPickerMode.RGB; - [Parameter] public bool ShowToolbar { get; set; } = false; - [Parameter] public bool ShowColorField { get; set; } = true; - [Parameter] public bool ShowPreview { get; set; } = true; - [Parameter] public bool ShowSliders { get; set; } = true; - [Parameter] public bool DisableInput { get; set; } = false; - [Parameter] public bool ShowModeSwitch { get; set; } = true; - [Parameter] public bool ShowAlpha { get; set; } = true; - [Parameter] public bool DragEffect { get; set; } = true; - [Parameter] public ColorPickerView ViewMode { get; set; } = ColorPickerView.Spectrum; - [Parameter] public PickerVariant Variant { get; set; } = PickerVariant.Static; - [Parameter] public bool Required { get; set; } + [Parameter] + public bool Required { get; set; } - public async Task OpenPicker() + public Task OpenPicker() { - await InvokeAsync(() => + return InvokeAsync(async () => { - _picker.OpenAsync(); + await _picker.OpenAsync(); }); } - public async Task ClosePicker() + public Task ClosePicker() { - await InvokeAsync(async () => + return InvokeAsync(async () => { await _picker.CloseAsync(); }); diff --git a/src/MudBlazor.UnitTests.Viewer/TestComponents/DataGrid/DataGridAggregationTest.razor b/src/MudBlazor.UnitTests.Viewer/TestComponents/DataGrid/DataGridAggregationTest.razor index f220c23fd6e9..ace097cd01b8 100644 --- a/src/MudBlazor.UnitTests.Viewer/TestComponents/DataGrid/DataGridAggregationTest.razor +++ b/src/MudBlazor.UnitTests.Viewer/TestComponents/DataGrid/DataGridAggregationTest.razor @@ -1,14 +1,15 @@ -@namespace MudBlazor.UnitTests.TestComponents - - + - @{ int index = 1, count = @context.Items.Count(); } + @{ int index = 1, count = context.Items.Count(); } People: - @foreach (var person in @context.Items) + @foreach (var person in context.Items) { - @person.Name.First()@person.Name.Substring(1) + + @person?.Name.First() + + @person?.Name.Substring(1) if (index < count) { @(", ") @@ -32,32 +33,33 @@ @code { public record Model (string Name, int Age, Severity Status, decimal Salary, DateTime HireDate, bool IsManager); - IEnumerable _items = new List() + private readonly IEnumerable _items = new List { - new Model("Sam", 56, Severity.Normal, 50_000.00M, new DateTime(2005, 3, 5), false), - new Model("Alicia", 54, Severity.Info, 75_000.00M, new DateTime(2010, 1, 17), false), - new Model("Ira", 27, Severity.Success, 102_000.00M, new DateTime(2017, 6, 15), true), - new Model("John", 32, Severity.Warning, 132_000.00M, new DateTime(2021, 12, 23), true), - new Model("Fred", 65, Severity.Warning, 87_000.00M, new DateTime(2003, 7, 3), false), - new Model("Tabitha", 33, Severity.Info, 157_000.00M, new DateTime(2015, 2, 12), true), - new Model("Hunter", 22, Severity.Success, 43_000.00M, new DateTime(2017, 9, 20), false), - new Model("Esme", 55, Severity.Warning, 149_000.00M, new DateTime(2017, 8, 1), true) + new("Sam", 56, Severity.Normal, 50_000.00M, new DateTime(2005, 3, 5), false), + new("Alicia", 54, Severity.Info, 75_000.00M, new DateTime(2010, 1, 17), false), + new("Ira", 27, Severity.Success, 102_000.00M, new DateTime(2017, 6, 15), true), + new("John", 32, Severity.Warning, 132_000.00M, new DateTime(2021, 12, 23), true), + new("Fred", 65, Severity.Warning, 87_000.00M, new DateTime(2003, 7, 3), false), + new("Tabitha", 33, Severity.Info, 157_000.00M, new DateTime(2015, 2, 12), true), + new("Hunter", 22, Severity.Success, 43_000.00M, new DateTime(2017, 9, 20), false), + new("Esme", 55, Severity.Warning, 149_000.00M, new DateTime(2017, 8, 1), true) }; - AggregateDefinition _ageAggregation = new AggregateDefinition + + private readonly AggregateDefinition _ageAggregation = new() { Type = AggregateType.Avg, DisplayFormat = "Average age is {value}" }; - AggregateDefinition _salaryAggregation = new AggregateDefinition + private readonly AggregateDefinition _salaryAggregation = new() { Type = AggregateType.Custom, CustomAggregate = x => { var highestSalary = x.Max(z => z.Salary); var countOver100Grand = x.Count(z => z.Salary > 100_000); - return $"Highest: {highestSalary.ToString("C0")} | {countOver100Grand} Over {100000:C0}"; + return $"Highest: {highestSalary:C0} | {countOver100Grand} Over {100000:C0}"; } }; } \ No newline at end of file diff --git a/src/MudBlazor.UnitTests.Viewer/TestComponents/DataGrid/DataGridCellContextTest.razor b/src/MudBlazor.UnitTests.Viewer/TestComponents/DataGrid/DataGridCellContextTest.razor index b7a58735f631..2fb45b335ccb 100644 --- a/src/MudBlazor.UnitTests.Viewer/TestComponents/DataGrid/DataGridCellContextTest.razor +++ b/src/MudBlazor.UnitTests.Viewer/TestComponents/DataGrid/DataGridCellContextTest.razor @@ -1,6 +1,4 @@ -@namespace MudBlazor.UnitTests.TestComponents - - + @@ -8,11 +6,11 @@ @code { - private IEnumerable _items = new List() + private readonly IEnumerable _items = new List { - new Model("John", 45), - new Model("Johanna", 23), - new Model("Steve", 32) + new("John", 45), + new("Johanna", 23), + new("Steve", 32) }; public record Model(string Name, int Age); diff --git a/src/MudBlazor.UnitTests.Viewer/TestComponents/DataGrid/DataGridCellEditTest.razor b/src/MudBlazor.UnitTests.Viewer/TestComponents/DataGrid/DataGridCellEditTest.razor index 8f6db6367cc9..e5be0d32f2b0 100644 --- a/src/MudBlazor.UnitTests.Viewer/TestComponents/DataGrid/DataGridCellEditTest.razor +++ b/src/MudBlazor.UnitTests.Viewer/TestComponents/DataGrid/DataGridCellEditTest.razor @@ -1,6 +1,4 @@ -@namespace MudBlazor.UnitTests.TestComponents - - + @@ -8,11 +6,11 @@ @code { - private IEnumerable _items = new List() + private readonly IEnumerable _items = new List { - new Model("John", 45), - new Model("Johanna", 23), - new Model("Steve", 32) + new("John", 45), + new("Johanna", 23), + new("Steve", 32) }; public record Model(string Name, int Age); diff --git a/src/MudBlazor.UnitTests.Viewer/TestComponents/DataGrid/DataGridCellEditVirtualizeServerDataTest.razor b/src/MudBlazor.UnitTests.Viewer/TestComponents/DataGrid/DataGridCellEditVirtualizeServerDataTest.razor index e8460648650b..c81bbaabf881 100644 --- a/src/MudBlazor.UnitTests.Viewer/TestComponents/DataGrid/DataGridCellEditVirtualizeServerDataTest.razor +++ b/src/MudBlazor.UnitTests.Viewer/TestComponents/DataGrid/DataGridCellEditVirtualizeServerDataTest.razor @@ -1,6 +1,3 @@ -@using System.Threading -@namespace MudBlazor.UnitTests.TestComponents - @@ -11,11 +8,11 @@ @code { public static string __description__ = @"Test editing values in cells of the DataGrid."; - private readonly IEnumerable _items = new List() + private readonly IEnumerable _items = new List { - new Item("John", 45), - new Item("Johanna", 23), - new Item("Steve", 32) + new("John", 45), + new("Johanna", 23), + new("Steve", 32) }; public record Item(string Name, int Age); diff --git a/src/MudBlazor.UnitTests.Viewer/TestComponents/DataGrid/DataGridCellEditWithNullableChangeTest.razor b/src/MudBlazor.UnitTests.Viewer/TestComponents/DataGrid/DataGridCellEditWithNullableChangeTest.razor index 2d4ba3229753..924174e1cbdf 100644 --- a/src/MudBlazor.UnitTests.Viewer/TestComponents/DataGrid/DataGridCellEditWithNullableChangeTest.razor +++ b/src/MudBlazor.UnitTests.Viewer/TestComponents/DataGrid/DataGridCellEditWithNullableChangeTest.razor @@ -1,6 +1,4 @@ -@namespace MudBlazor.UnitTests.TestComponents - - + @@ -8,11 +6,11 @@ @code { - public IEnumerable _items = new List() + private readonly IEnumerable _items = new List { - new Model("John", 45), - new Model("Johanna", 23), - new Model("Steve", null) + new("John", 45), + new("Johanna", 23), + new("Steve", null) }; public record Model(string Name, int? Age); diff --git a/src/MudBlazor.UnitTests.Viewer/TestComponents/DataGrid/DataGridCellEditWithNullableTest.razor b/src/MudBlazor.UnitTests.Viewer/TestComponents/DataGrid/DataGridCellEditWithNullableTest.razor index b02b041400cb..924174e1cbdf 100644 --- a/src/MudBlazor.UnitTests.Viewer/TestComponents/DataGrid/DataGridCellEditWithNullableTest.razor +++ b/src/MudBlazor.UnitTests.Viewer/TestComponents/DataGrid/DataGridCellEditWithNullableTest.razor @@ -1,6 +1,4 @@ -@namespace MudBlazor.UnitTests.TestComponents - - + @@ -8,13 +6,12 @@ @code { - private IEnumerable _items = new List() + private readonly IEnumerable _items = new List { - new Model("John", 45), - new Model("Johanna", 23), - new Model("Steve", null) + new("John", 45), + new("Johanna", 23), + new("Steve", null) }; public record Model(string Name, int? Age); - } diff --git a/src/MudBlazor.UnitTests.Viewer/TestComponents/DataGrid/DataGridCellEditWithTemplateTest.razor b/src/MudBlazor.UnitTests.Viewer/TestComponents/DataGrid/DataGridCellEditWithTemplateTest.razor index 9bf6c966af55..4367dc80f414 100644 --- a/src/MudBlazor.UnitTests.Viewer/TestComponents/DataGrid/DataGridCellEditWithTemplateTest.razor +++ b/src/MudBlazor.UnitTests.Viewer/TestComponents/DataGrid/DataGridCellEditWithTemplateTest.razor @@ -1,6 +1,4 @@ -@namespace MudBlazor.UnitTests.TestComponents - - + @@ -13,25 +11,17 @@ @code { - private IEnumerable _items = new List() + private readonly IEnumerable _items = new List { - new Model("John", 45, false), - new Model("Johanna", 23, true), - new Model("Steve", 32, false) + new("John", 45, false), + new("Johanna", 23, true), + new("Steve", 32, false) }; - public class Model + public class Model(string name, int age, bool hired) { - public string Name { get; set; } - public int Age { get; set; } - public bool Hired { get; set; } - - public Model(string name, int age, bool hired) - { - this.Name = name; - this.Age = age; - this.Hired = hired; - } - + public string Name { get; set; } = name; + public int Age { get; set; } = age; + public bool Hired { get; set; } = hired; } } diff --git a/src/MudBlazor.UnitTests.Viewer/TestComponents/DataGrid/DataGridCellTemplateTest.razor b/src/MudBlazor.UnitTests.Viewer/TestComponents/DataGrid/DataGridCellTemplateTest.razor index 4c0f9374b0ef..7e36eb886f8e 100644 --- a/src/MudBlazor.UnitTests.Viewer/TestComponents/DataGrid/DataGridCellTemplateTest.razor +++ b/src/MudBlazor.UnitTests.Viewer/TestComponents/DataGrid/DataGridCellTemplateTest.razor @@ -1,6 +1,4 @@ -@namespace MudBlazor.UnitTests.TestComponents - - + @@ -16,25 +14,17 @@ @code { - private IEnumerable _items = new List() + private readonly IEnumerable _items = new List { - new Model("John", 45, false), - new Model("Johanna", 23, true), - new Model("Steve", 32, false) + new("John", 45, false), + new("Johanna", 23, true), + new("Steve", 32, false) }; - public class Model + public class Model(string name, int age, bool hired) { - public string Name { get; set; } - public int Age { get; set; } - public bool Hired { get; set; } - - public Model(string name, int age, bool hired) - { - this.Name = name; - this.Age = age; - this.Hired = hired; - } - + public string Name { get; set; } = name; + public int Age { get; set; } = age; + public bool Hired { get; set; } = hired; } } diff --git a/src/MudBlazor.UnitTests.Viewer/TestComponents/DataGrid/DataGridChildPropertiesWithSameNameSortTest.razor b/src/MudBlazor.UnitTests.Viewer/TestComponents/DataGrid/DataGridChildPropertiesWithSameNameSortTest.razor index 029c5253a29a..ebf53fbae2b1 100644 --- a/src/MudBlazor.UnitTests.Viewer/TestComponents/DataGrid/DataGridChildPropertiesWithSameNameSortTest.razor +++ b/src/MudBlazor.UnitTests.Viewer/TestComponents/DataGrid/DataGridChildPropertiesWithSameNameSortTest.razor @@ -1,6 +1,4 @@ -@namespace MudBlazor.UnitTests.TestComponents - - + @@ -10,7 +8,7 @@ @code { public record Employee(string Name, Manager Manager); public record Manager(string Name); - private IEnumerable _employees; + private IEnumerable _employees = []; protected override void OnInitialized() { diff --git a/src/MudBlazor.UnitTests.Viewer/TestComponents/DataGrid/DataGridChildRowContentTest.razor b/src/MudBlazor.UnitTests.Viewer/TestComponents/DataGrid/DataGridChildRowContentTest.razor index 82467f627e99..2460312d1899 100644 --- a/src/MudBlazor.UnitTests.Viewer/TestComponents/DataGrid/DataGridChildRowContentTest.razor +++ b/src/MudBlazor.UnitTests.Viewer/TestComponents/DataGrid/DataGridChildRowContentTest.razor @@ -1,6 +1,4 @@ -@namespace MudBlazor.UnitTests.TestComponents - - + @@ -12,7 +10,7 @@ @code { - private IEnumerable _items = new List() + private readonly IEnumerable _items = new List() { new Model("Sam", 56, Severity.Normal), new Model("Alicia", 54, Severity.Info), diff --git a/src/MudBlazor.UnitTests.Viewer/TestComponents/DataGrid/DataGridColGroupTest.razor b/src/MudBlazor.UnitTests.Viewer/TestComponents/DataGrid/DataGridColGroupTest.razor index 8910995d4907..69bebe16e377 100644 --- a/src/MudBlazor.UnitTests.Viewer/TestComponents/DataGrid/DataGridColGroupTest.razor +++ b/src/MudBlazor.UnitTests.Viewer/TestComponents/DataGrid/DataGridColGroupTest.razor @@ -1,6 +1,4 @@ -@namespace MudBlazor.UnitTests.TestComponents - - + @@ -14,7 +12,7 @@ @code { - private IEnumerable _items = new List() + private readonly IEnumerable _items = new List() { new Model("Sam", 56, Severity.Normal), new Model("Alicia", 54, Severity.Info), diff --git a/src/MudBlazor.UnitTests.Viewer/TestComponents/DataGrid/DataGridColReorderRowFiltersTest.razor b/src/MudBlazor.UnitTests.Viewer/TestComponents/DataGrid/DataGridColReorderRowFiltersTest.razor index 7f5a044638d4..fef955415472 100644 --- a/src/MudBlazor.UnitTests.Viewer/TestComponents/DataGrid/DataGridColReorderRowFiltersTest.razor +++ b/src/MudBlazor.UnitTests.Viewer/TestComponents/DataGrid/DataGridColReorderRowFiltersTest.razor @@ -1,5 +1,4 @@ -@namespace MudBlazor.UnitTests.TestComponents - + @@ -16,14 +15,14 @@ @code { - MudDataGrid _dataGrid; + private MudDataGrid _dataGrid = null!; - private IEnumerable _items = new List() + private readonly IEnumerable _items = new List { - new Model("Sam", 56, Severity.Normal, false, null, null), - new Model("Alicia", 54, Severity.Info, null, null, new Guid("b7accfd5-928d-48ad-8a0c-9448ae37bf96")), - new Model("Ira", 27, Severity.Success, true, new DateTime(2011, 1, 2), null), - new Model("John", 32, Severity.Warning, false, null, null) + new("Sam", 56, Severity.Normal, false, null, null), + new("Alicia", 54, Severity.Info, null, null, new Guid("b7accfd5-928d-48ad-8a0c-9448ae37bf96")), + new("Ira", 27, Severity.Success, true, new DateTime(2011, 1, 2), null), + new("John", 32, Severity.Warning, false, null, null) }; public record Model (string Name, int? Age, Severity? Status, bool? Hired, DateTime? HiredOn, Guid? ApplicationId); diff --git a/src/MudBlazor.UnitTests.Viewer/TestComponents/DataGrid/DataGridColumnChooserTest.razor b/src/MudBlazor.UnitTests.Viewer/TestComponents/DataGrid/DataGridColumnChooserTest.razor index 2d886d5f9ddf..69b982822e83 100644 --- a/src/MudBlazor.UnitTests.Viewer/TestComponents/DataGrid/DataGridColumnChooserTest.razor +++ b/src/MudBlazor.UnitTests.Viewer/TestComponents/DataGrid/DataGridColumnChooserTest.razor @@ -1,28 +1,27 @@ -@namespace MudBlazor.UnitTests.TestComponents - - + @code { - private bool hiddenAge = false; - private bool hiddenProp1; - private bool hiddenProp3 = false; - private bool hiddenProp4; - private readonly IEnumerable _items = new List() + private readonly bool _hiddenAge = false; + private bool _hiddenProp1; + private readonly bool _hiddenProp3 = false; + private bool _hiddenProp4; + + private readonly IEnumerable _items = new List { - new Model("John", 45, true, true, true, true), - new Model("Johanna", 23, true, true, true, true), - new Model("Steve", 32, true, true, true, true) + new("John", 45, true, true, true, true), + new("Johanna", 23, true, true, true, true), + new("Steve", 32, true, true, true, true) }; public record Model(string Name, int Age, bool Prop1, bool Prop2, bool Prop3, bool Prop4); diff --git a/src/MudBlazor.UnitTests.Viewer/TestComponents/DataGrid/DataGridColumnFilterRowPropertyTest.razor b/src/MudBlazor.UnitTests.Viewer/TestComponents/DataGrid/DataGridColumnFilterRowPropertyTest.razor index bc3b78a33d6a..d7e280b62bf6 100644 --- a/src/MudBlazor.UnitTests.Viewer/TestComponents/DataGrid/DataGridColumnFilterRowPropertyTest.razor +++ b/src/MudBlazor.UnitTests.Viewer/TestComponents/DataGrid/DataGridColumnFilterRowPropertyTest.razor @@ -1,6 +1,4 @@ -@namespace MudBlazor.UnitTests.TestComponents - - + Clear All Filters @@ -16,7 +14,7 @@ @code { public record Model (string Name, int? Age, Severity? Status, bool? Hired, DateTime? HiredOn); - private MudDataGrid _dataGrid; + private MudDataGrid _dataGrid = null!; protected override void OnAfterRender(bool firstRender) { @@ -34,18 +32,18 @@ } } - private void AddFilter(int columnIndex, object value) + private void AddFilter(int columnIndex, object? value) { var filter = _dataGrid.RenderedColumns[columnIndex].FilterContext.FilterDefinition; filter!.Value = value; _dataGrid.FilterDefinitions.Add(filter); } - private readonly IEnumerable _items = new List() + private readonly IEnumerable _items = new List { - new Model("Sam", 56, Severity.Normal, false, null), - new Model("Alicia", 54, Severity.Info, null, null), - new Model("Ira", 27, Severity.Success, true, new DateTime(2011, 1, 2)), - new Model("John", 32, Severity.Warning, false, null) + new("Sam", 56, Severity.Normal, false, null), + new("Alicia", 54, Severity.Info, null, null), + new("Ira", 27, Severity.Success, true, new DateTime(2011, 1, 2)), + new("John", 32, Severity.Warning, false, null) }; } \ No newline at end of file diff --git a/src/MudBlazor.UnitTests.Viewer/TestComponents/DataGrid/DataGridColumnGroupingTest.razor b/src/MudBlazor.UnitTests.Viewer/TestComponents/DataGrid/DataGridColumnGroupingTest.razor index 762a79b9a135..25b8ce643eb8 100644 --- a/src/MudBlazor.UnitTests.Viewer/TestComponents/DataGrid/DataGridColumnGroupingTest.razor +++ b/src/MudBlazor.UnitTests.Viewer/TestComponents/DataGrid/DataGridColumnGroupingTest.razor @@ -1,6 +1,4 @@ -@namespace MudBlazor.UnitTests.TestComponents - - + @@ -16,23 +14,17 @@ public bool IsGenderGrouped { get; set; } public bool IsAgeGrouped { get; set; } - public List _items = new List() - { - new Model("John", 45, "Male"), - new Model("Johanna", 23, "Female"), - new Model("Steve", 32, "Male"), - new Model("Alice", 32, "Female") - }; + private readonly List _items = + [ + new("John", 45, "Male"), + new("Johanna", 23, "Female"), + new("Steve", 32, "Male"), + new("Alice", 32, "Female") + ]; public record Model(string Name, int Age, string Gender); - void GroupByGender(MouseEventArgs args) - { - IsGenderGrouped = true; - } + private void GroupByGender(MouseEventArgs args) => IsGenderGrouped = true; - void GroupByAge(MouseEventArgs args) - { - IsAgeGrouped = true; - } + private void GroupByAge(MouseEventArgs args) => IsAgeGrouped = true; } diff --git a/src/MudBlazor.UnitTests.Viewer/TestComponents/DataGrid/DataGridColumnHiddenTest.razor b/src/MudBlazor.UnitTests.Viewer/TestComponents/DataGrid/DataGridColumnHiddenTest.razor index 542535e2f3bd..36d256d6bd81 100644 --- a/src/MudBlazor.UnitTests.Viewer/TestComponents/DataGrid/DataGridColumnHiddenTest.razor +++ b/src/MudBlazor.UnitTests.Viewer/TestComponents/DataGrid/DataGridColumnHiddenTest.razor @@ -1,29 +1,27 @@ -@namespace MudBlazor.UnitTests.TestComponents - - + @code { - private bool hiddenAge = true; - private bool hiddenProp1; - private bool hiddenProp3 = false; - private bool hiddenProp4; - private readonly IEnumerable _items = new List() + private readonly bool _hiddenAge = true; + private bool _hiddenProp1; + private readonly bool _hiddenProp3 = false; + private bool _hiddenProp4; + private readonly IEnumerable _items = new List { - new Model("John", 45, true, true, true, true), - new Model("Johanna", 23, true, true, true, true), - new Model("Steve", 32, true, true, true, true) + new("John", 45, true, true, true, true), + new("Johanna", 23, true, true, true, true), + new("Steve", 32, true, true, true, true) }; public record Model(string Name, int Age, bool Prop1, bool Prop2, bool Prop3, bool Prop4); } \ No newline at end of file diff --git a/src/MudBlazor.UnitTests.Viewer/TestComponents/DataGrid/DataGridColumnPopupCustomFilteringTest.razor b/src/MudBlazor.UnitTests.Viewer/TestComponents/DataGrid/DataGridColumnPopupCustomFilteringTest.razor index f86ba17f7ce5..861b7261adca 100644 --- a/src/MudBlazor.UnitTests.Viewer/TestComponents/DataGrid/DataGridColumnPopupCustomFilteringTest.razor +++ b/src/MudBlazor.UnitTests.Viewer/TestComponents/DataGrid/DataGridColumnPopupCustomFilteringTest.razor @@ -1,7 +1,6 @@ -@namespace MudBlazor.UnitTests.TestComponents - + - + @@ -18,21 +17,21 @@ - @code { +@code { public record Model (string Name, int? Age, Severity? Status, bool? Hired, DateTime? HiredOn); - MudDataGrid grid; + private MudDataGrid _grid = null!; - private IEnumerable _items = new List() + private readonly IEnumerable _items = new List { - new Model("Sam", 56, Severity.Normal, false, null), - new Model("Alicia", 54, Severity.Info, null, null), - new Model("Ira", 27, Severity.Success, true, new DateTime(2011, 1, 2)), - new Model("John", 32, Severity.Warning, false, null) + new("Sam", 56, Severity.Normal, false, null), + new("Alicia", 54, Severity.Info, null, null), + new("Ira", 27, Severity.Success, true, new DateTime(2011, 1, 2)), + new("John", 32, Severity.Warning, false, null) }; public bool FilterHired; - FilterDefinition _filterDefinition = new(); + private FilterDefinition _filterDefinition = new(); protected override void OnAfterRender(bool firstRender) { @@ -40,7 +39,7 @@ { _filterDefinition = new FilterDefinition { - Column = grid.RenderedColumns.FirstOrDefault(x => x.PropertyName == "Hired"), + Column = _grid.RenderedColumns.FirstOrDefault(x => x.PropertyName == "Hired"), Operator = FilterOperator.Boolean.Is, Value = true }; diff --git a/src/MudBlazor.UnitTests.Viewer/TestComponents/DataGrid/DataGridColumnPopupFilteringTest.razor b/src/MudBlazor.UnitTests.Viewer/TestComponents/DataGrid/DataGridColumnPopupFilteringTest.razor index ec613515b956..8a9433b80cc7 100644 --- a/src/MudBlazor.UnitTests.Viewer/TestComponents/DataGrid/DataGridColumnPopupFilteringTest.razor +++ b/src/MudBlazor.UnitTests.Viewer/TestComponents/DataGrid/DataGridColumnPopupFilteringTest.razor @@ -1,5 +1,4 @@ -@namespace MudBlazor.UnitTests.TestComponents - + @@ -14,11 +13,11 @@ @code { public record Model (string Name, int? Age, Severity? Status, bool? Hired, DateTime? HiredOn); - private IEnumerable _items = new List() + private readonly IEnumerable _items = new List() { - new Model("Sam", 56, Severity.Normal, false, null), - new Model("Alicia", 54, Severity.Info, null, null), - new Model("Ira", 27, Severity.Success, true, new DateTime(2011, 1, 2)), - new Model("John", 32, Severity.Warning, false, null) + new("Sam", 56, Severity.Normal, false, null), + new("Alicia", 54, Severity.Info, null, null), + new("Ira", 27, Severity.Success, true, new DateTime(2011, 1, 2)), + new("John", 32, Severity.Warning, false, null) }; } diff --git a/src/MudBlazor.UnitTests.Viewer/TestComponents/DataGrid/DataGridConditionalLogicOnColumnsTest.razor b/src/MudBlazor.UnitTests.Viewer/TestComponents/DataGrid/DataGridConditionalLogicOnColumnsTest.razor index 12dd3b40fe93..ec2b3966ba31 100644 --- a/src/MudBlazor.UnitTests.Viewer/TestComponents/DataGrid/DataGridConditionalLogicOnColumnsTest.razor +++ b/src/MudBlazor.UnitTests.Viewer/TestComponents/DataGrid/DataGridConditionalLogicOnColumnsTest.razor @@ -1,6 +1,4 @@ -@namespace MudBlazor.UnitTests.TestComponents - - +
/// - /// Defaults to button, - /// or a if is set. + /// Defaults to button, + /// or a if is set. /// [Parameter] [Category(CategoryTypes.Button.ClickAction)] diff --git a/src/MudBlazor/Components/Alert/MudAlert.razor.cs b/src/MudBlazor/Components/Alert/MudAlert.razor.cs index 71eddf5be152..0799d3b93a25 100644 --- a/src/MudBlazor/Components/Alert/MudAlert.razor.cs +++ b/src/MudBlazor/Components/Alert/MudAlert.razor.cs @@ -15,16 +15,16 @@ namespace MudBlazor public partial class MudAlert : MudComponentBase { protected string Classname => new CssBuilder("mud-alert") - .AddClass($"mud-alert-{Variant.ToDescriptionString()}-{Severity.ToDescriptionString()}") - .AddClass($"mud-dense", Dense) - .AddClass($"mud-square", Square) - .AddClass($"mud-elevation-{Elevation}") - .AddClass(Class) - .Build(); + .AddClass($"mud-alert-{Variant.ToDescriptionString()}-{Severity.ToDescriptionString()}") + .AddClass($"mud-dense", Dense) + .AddClass($"mud-square", Square) + .AddClass($"mud-elevation-{Elevation}") + .AddClass(Class) + .Build(); protected string ClassPosition => new CssBuilder("mud-alert-position") - .AddClass($"justify-sm-{ConvertHorizontalAlignment(ContentAlignment).ToDescriptionString()}") - .Build(); + .AddClass($"justify-sm-{ConvertHorizontalAlignment(ContentAlignment).ToDescriptionString()}") + .Build(); /// /// Gets the horizontal alignment to use based on the current right-to-left setting. diff --git a/src/MudBlazor/Components/Autocomplete/MudAutocomplete.razor b/src/MudBlazor/Components/Autocomplete/MudAutocomplete.razor index 19d80df39876..92785e31f8e4 100644 --- a/src/MudBlazor/Components/Autocomplete/MudAutocomplete.razor +++ b/src/MudBlazor/Components/Autocomplete/MudAutocomplete.razor @@ -35,7 +35,8 @@ HelperText="@HelperText" OnAdornmentClick="@AdornmentClickHandlerAsync" AdornmentIcon="@CurrentIcon" Adornment="@Adornment" AdornmentColor="@AdornmentColor" IconSize="@IconSize" AdornmentText="@AdornmentText" AdornmentAriaLabel="@AdornmentAriaLabel" - Clearable="@(!GetReadOnlyState() && Clearable)" OnClearButtonClick="@OnClearButtonClick" + Clearable="@(Clearable && !GetReadOnlyState())" + OnClearButtonClick="@OnClearButtonClick" ClearIcon="@ClearIcon" MaxLength="@MaxLength" autocomplete="@GetAutocomplete()" diff --git a/src/MudBlazor/Components/Autocomplete/MudAutocomplete.razor.cs b/src/MudBlazor/Components/Autocomplete/MudAutocomplete.razor.cs index 2c5210d4a116..87841ffd33c7 100644 --- a/src/MudBlazor/Components/Autocomplete/MudAutocomplete.razor.cs +++ b/src/MudBlazor/Components/Autocomplete/MudAutocomplete.razor.cs @@ -41,8 +41,8 @@ public partial class MudAutocomplete : MudBaseInput protected string Classname => new CssBuilder("mud-select") - .AddClass(Class) - .Build(); + .AddClass(Class) + .Build(); protected string InputClassname => new CssBuilder("mud-select-input") @@ -51,21 +51,21 @@ public partial class MudAutocomplete : MudBaseInput protected string AutocompleteClassname => new CssBuilder("mud-select") - .AddClass("mud-autocomplete") - .AddClass("mud-width-full", FullWidth) - .AddClass("mud-autocomplete--with-progress", ShowProgressIndicator && IsLoading) - .Build(); + .AddClass("mud-autocomplete") + .AddClass("mud-width-full", FullWidth) + .AddClass("mud-autocomplete--with-progress", ShowProgressIndicator && IsLoading) + .Build(); protected string CircularProgressClassname => new CssBuilder("progress-indicator-circular") - .AddClass("progress-indicator-circular--with-adornment", Adornment == Adornment.End) - .Build(); + .AddClass("progress-indicator-circular--with-adornment", Adornment == Adornment.End) + .Build(); protected string GetListItemClassname(bool isSelected) => new CssBuilder() - .AddClass("mud-selected-item mud-primary-text mud-primary-hover", isSelected) - .AddClass(ListItemClass) - .Build(); + .AddClass("mud-selected-item mud-primary-text mud-primary-hover", isSelected) + .AddClass(ListItemClass) + .Build(); /// /// Input's classnames, separated by space. @@ -108,21 +108,21 @@ protected string GetListItemClassname(bool isSelected) => /// The location where the popover will open from. /// /// - /// Defaults to . + /// Defaults to . /// [Parameter] [Category(CategoryTypes.FormComponent.ListAppearance)] - public Origin AnchorOrigin { get; set; } = Origin.BottomCenter; + public Origin AnchorOrigin { get; set; } = Origin.BottomLeft; /// /// The transform origin point for the popover. /// /// - /// Defaults to . + /// Defaults to . /// [Parameter] [Category(CategoryTypes.FormComponent.ListAppearance)] - public Origin TransformOrigin { get; set; } = Origin.TopCenter; + public Origin TransformOrigin { get; set; } = Origin.TopLeft; /// /// Uses compact padding. @@ -750,11 +750,11 @@ public async Task ClearAsync() _isCleared = true; Open = false; - await SetTextAsync(null, updateValue: false); - await CoerceValueToTextAsync(); + await SetTextAsync("", updateValue: false); + await SetValueAsync(default(T), updateText: false); if (_elementReference != null) - await _elementReference.SetText(""); + await _elementReference.ResetAsync(); _debounceTimer?.Dispose(); StateHasChanged(); @@ -789,9 +789,8 @@ private async Task OnInputKeyDownAsync(KeyboardEventArgs args) { if (SelectValueOnTab) await OnEnterKeyAsync(); - else - Open = false; } + await CloseMenuAsync(); break; case "ArrowDown": if (Open) @@ -977,6 +976,9 @@ private Task CoerceTextToValueAsync() if (!CoerceText) return Task.CompletedTask; + if (ResetValueOnEmptyText && string.IsNullOrEmpty(Text)) + return Task.CompletedTask; + _debounceTimer?.Dispose(); var text = Value == null ? null : GetItemString(Value); diff --git a/src/MudBlazor/Components/Breadcrumbs/BreadcrumbLink.razor b/src/MudBlazor/Components/Breadcrumbs/BreadcrumbLink.razor index 77e7a37e9337..5feb921d4d6c 100644 --- a/src/MudBlazor/Components/Breadcrumbs/BreadcrumbLink.razor +++ b/src/MudBlazor/Components/Breadcrumbs/BreadcrumbLink.razor @@ -14,6 +14,6 @@ } else { - @Parent?.ItemTemplate(Item); + @Parent?.ItemTemplate(Item) } diff --git a/src/MudBlazor/Components/DataGrid/Column.razor.cs b/src/MudBlazor/Components/DataGrid/Column.razor.cs index 6e4003b5146c..32cd868059c6 100644 --- a/src/MudBlazor/Components/DataGrid/Column.razor.cs +++ b/src/MudBlazor/Components/DataGrid/Column.razor.cs @@ -445,13 +445,13 @@ public CultureInfo Culture .AddClass("sticky-left", StickyLeft) .AddClass("sticky-right", StickyRight) .AddClass(Class) - .Build(); + .Build(); internal string footerClassname => new CssBuilder("mud-table-cell") .AddClass("mud-table-cell-hide", HideSmall) .AddClass(Class) - .Build(); + .Build(); #region Computed Properties diff --git a/src/MudBlazor/Components/DataGrid/FooterCell.razor.cs b/src/MudBlazor/Components/DataGrid/FooterCell.razor.cs index db9cdd15fa9e..7cc47afef0bf 100644 --- a/src/MudBlazor/Components/DataGrid/FooterCell.razor.cs +++ b/src/MudBlazor/Components/DataGrid/FooterCell.razor.cs @@ -45,14 +45,15 @@ public partial class FooterCell : MudComponentBase .AddClass(Column?.FooterClass) .AddClass(Column?.footerClassname) .AddClass(Class) - .Build(); + .Build(); + private string _style => new StyleBuilder() .AddStyle(Column?.FooterStyleFunc?.Invoke(items ?? Enumerable.Empty())) .AddStyle(Column?.FooterStyle) .AddStyle(Style) .AddStyle("font-weight", "600") - .Build(); + .Build(); internal IEnumerable items { diff --git a/src/MudBlazor/Components/DataGrid/HeaderCell.razor b/src/MudBlazor/Components/DataGrid/HeaderCell.razor index 2de072635af2..68bb39c537db 100644 --- a/src/MudBlazor/Components/DataGrid/HeaderCell.razor +++ b/src/MudBlazor/Components/DataGrid/HeaderCell.razor @@ -102,7 +102,7 @@ else if (Column != null && !Column.HiddenState.Value) @if (showColumnOptions) { - + @Localizer[LanguageResource.MudDataGrid_Unsort] @if (filterable && DataGrid.FilterMode != DataGridFilterMode.ColumnFilterRow) { diff --git a/src/MudBlazor/Components/DataGrid/HeaderCell.razor.cs b/src/MudBlazor/Components/DataGrid/HeaderCell.razor.cs index 5b2a48cbbb74..acfa8ddd2180 100644 --- a/src/MudBlazor/Components/DataGrid/HeaderCell.razor.cs +++ b/src/MudBlazor/Components/DataGrid/HeaderCell.razor.cs @@ -72,7 +72,7 @@ public SortDirection SortDirection .AddClass(Column?.HeaderClassFunc?.Invoke(DataGrid?.CurrentPageItems ?? Enumerable.Empty())) .AddClass(Column?.headerClassname) .AddClass(Class) - .Build(); + .Build(); private string _style => new StyleBuilder() @@ -80,31 +80,31 @@ public SortDirection SortDirection .AddStyle(Column?.HeaderStyle) .AddStyle("width", Width?.ToPx(), when: Width.HasValue) .AddStyle(Style) - .Build(); + .Build(); private string _resizerStyle => new StyleBuilder() .AddStyle("height", _resizerHeight?.ToPx() ?? "100%") .AddStyle(Style) - .Build(); + .Build(); private string _resizerClass => new CssBuilder() .AddClass("mud-resizing", when: _isResizing) .AddClass("mud-resizer") - .Build(); + .Build(); private string _sortHeaderClass => new CssBuilder() .AddClass("sortable-column-header") .AddClass("cursor-pointer", when: !_isResizing) - .Build(); + .Build(); private string _optionsClass => new CssBuilder() .AddClass("column-options") .AddClass("cursor-pointer", when: !_isResizing) - .Build(); + .Build(); private ElementReference _headerElement; diff --git a/src/MudBlazor/Components/DataGrid/MudDataGrid.razor b/src/MudBlazor/Components/DataGrid/MudDataGrid.razor index 37310e5db401..2ca18e854971 100644 --- a/src/MudBlazor/Components/DataGrid/MudDataGrid.razor +++ b/src/MudBlazor/Components/DataGrid/MudDataGrid.razor @@ -77,7 +77,8 @@ { - @@ -413,7 +414,7 @@ internal RenderFragment ToolbarMenu(MudDataGrid dataGrid) => @ - + @Localizer[LanguageResource.MudDataGrid_Columns] @if (dataGrid.Groupable) { diff --git a/src/MudBlazor/Components/DataGrid/MudDataGrid.razor.cs b/src/MudBlazor/Components/DataGrid/MudDataGrid.razor.cs index bbd3c0792045..63fc71144f17 100644 --- a/src/MudBlazor/Components/DataGrid/MudDataGrid.razor.cs +++ b/src/MudBlazor/Components/DataGrid/MudDataGrid.razor.cs @@ -39,32 +39,33 @@ public partial class MudDataGrid : MudComponentBase, IDisposable private MudDropContainer> _dropContainer; private MudDropContainer> _columnsPanelDropContainer; private CancellationTokenSource _serverDataCancellationTokenSource; + protected string _classname => new CssBuilder("mud-table") - .AddClass("mud-data-grid") - .AddClass("mud-xs-table", Breakpoint == Breakpoint.Xs) - .AddClass("mud-sm-table", Breakpoint == Breakpoint.Sm) - .AddClass("mud-md-table", Breakpoint == Breakpoint.Md) - .AddClass("mud-lg-table", Breakpoint == Breakpoint.Lg || Breakpoint == Breakpoint.Always) - .AddClass("mud-xl-table", Breakpoint == Breakpoint.Xl || Breakpoint == Breakpoint.Always) - .AddClass("mud-table-dense", Dense) - .AddClass("mud-table-hover", Hover) - .AddClass("mud-table-bordered", Bordered) - .AddClass("mud-table-striped", Striped) - .AddClass("mud-table-outlined", Outlined) - .AddClass("mud-table-square", Square) - .AddClass("mud-table-sticky-header", FixedHeader) - .AddClass("mud-table-sticky-footer", FixedFooter) - .AddClass($"mud-elevation-{Elevation}", !Outlined) - .AddClass(Class) - .Build(); + .AddClass("mud-data-grid") + .AddClass("mud-xs-table", Breakpoint == Breakpoint.Xs) + .AddClass("mud-sm-table", Breakpoint == Breakpoint.Sm) + .AddClass("mud-md-table", Breakpoint == Breakpoint.Md) + .AddClass("mud-lg-table", Breakpoint == Breakpoint.Lg || Breakpoint == Breakpoint.Always) + .AddClass("mud-xl-table", Breakpoint == Breakpoint.Xl || Breakpoint == Breakpoint.Always) + .AddClass("mud-table-dense", Dense) + .AddClass("mud-table-hover", Hover) + .AddClass("mud-table-bordered", Bordered) + .AddClass("mud-table-striped", Striped) + .AddClass("mud-table-outlined", Outlined) + .AddClass("mud-table-square", Square) + .AddClass("mud-table-sticky-header", FixedHeader) + .AddClass("mud-table-sticky-footer", FixedFooter) + .AddClass($"mud-elevation-{Elevation}", !Outlined) + .AddClass(Class) + .Build(); protected string _style => new StyleBuilder() .AddStyle("overflow-x", "auto", when: HorizontalScrollbar || ColumnResizeMode == ResizeMode.Container) .AddStyle("position", "relative", when: hasStickyColumns) .AddStyle(Style) - .Build(); + .Build(); protected string _tableStyle => new StyleBuilder() @@ -72,22 +73,27 @@ public partial class MudDataGrid : MudComponentBase, IDisposable .AddStyle("width", "max-content", when: HorizontalScrollbar || ColumnResizeMode == ResizeMode.Container) .AddStyle("overflow", "clip", when: (HorizontalScrollbar || ColumnResizeMode == ResizeMode.Container) && hasStickyColumns) .AddStyle("display", "block", when: HorizontalScrollbar) - .Build(); + .Build(); + protected string _tableClass => new CssBuilder("mud-table-container") .AddClass("cursor-col-resize", when: IsResizing) - .Build(); + .Build(); + + protected string _headClassname => + new CssBuilder("mud-table-head") + .AddClass(HeaderClass) + .Build(); - protected string _headClassname => new CssBuilder("mud-table-head") - .AddClass(HeaderClass).Build(); + protected string _footClassname => + new CssBuilder("mud-table-foot") + .AddClass(FooterClass).Build(); - protected string _footClassname => new CssBuilder("mud-table-foot") - .AddClass(FooterClass).Build(); protected string _headerFooterStyle => new StyleBuilder() .AddStyle("position", "sticky", when: hasStickyColumns) .AddStyle("left", "0px", when: hasStickyColumns) - .Build(); + .Build(); protected override void OnParametersSet() { diff --git a/src/MudBlazor/Components/DataGrid/MudDataGridPager.razor.cs b/src/MudBlazor/Components/DataGrid/MudDataGridPager.razor.cs index b2d12e5e187a..9a32c97d5218 100644 --- a/src/MudBlazor/Components/DataGrid/MudDataGridPager.razor.cs +++ b/src/MudBlazor/Components/DataGrid/MudDataGridPager.razor.cs @@ -119,8 +119,8 @@ private string Info protected string Classname => new CssBuilder("mud-table-pagination-toolbar") - .AddClass(Class) - .Build(); + .AddClass(Class) + .Build(); private async Task SetRowsPerPageAsync(int size) { diff --git a/src/MudBlazor/Components/DatePicker/MudDatePicker.cs b/src/MudBlazor/Components/DatePicker/MudDatePicker.cs index dbff725905df..3c32e100182a 100644 --- a/src/MudBlazor/Components/DatePicker/MudDatePicker.cs +++ b/src/MudBlazor/Components/DatePicker/MudDatePicker.cs @@ -1,6 +1,4 @@ -using System; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Components; +using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components.Web; using MudBlazor.Extensions; using MudBlazor.Utilities; @@ -14,6 +12,9 @@ public class MudDatePicker : MudBaseDatePicker { private DateTime? _selectedDate; + [Inject] + protected TimeProvider TimeProvider { get; set; } + /// /// Occurs when the has changed. /// @@ -99,7 +100,7 @@ protected override string GetDayClasses(int month, DateTime day) return b.AddClass("mud-hidden").Build(); if ((Date?.Date == day && _selectedDate == null) || _selectedDate?.Date == day) return b.AddClass("mud-selected").AddClass($"mud-theme-{Color.ToDescriptionString()}").Build(); - if (day == DateTime.Today) + if (day == TimeProvider.GetLocalNow().Date) return b.AddClass("mud-current mud-button-outlined").AddClass($"mud-button-outlined-{Color.ToDescriptionString()} mud-{Color.ToDescriptionString()}-text").Build(); return b.Build(); } @@ -212,13 +213,13 @@ protected override string GetTitleDateString() protected override DateTime GetCalendarStartOfMonth() { - var date = StartMonth ?? Date ?? DateTime.Today; + var date = StartMonth ?? Date ?? TimeProvider.GetLocalNow().Date; return date.StartOfMonth(Culture); } protected override int GetCalendarYear(DateTime yearDate) { - var date = Date ?? DateTime.Today; + var date = Date ?? TimeProvider.GetLocalNow().Date; var diff = Culture.Calendar.GetYear(date) - Culture.Calendar.GetYear(yearDate); var calenderYear = Culture.Calendar.GetYear(date); return calenderYear - diff; diff --git a/src/MudBlazor/Components/DatePicker/MudDateRangePicker.razor b/src/MudBlazor/Components/DatePicker/MudDateRangePicker.razor index 53d6201c75b6..15f73b4b82ba 100644 --- a/src/MudBlazor/Components/DatePicker/MudDateRangePicker.razor +++ b/src/MudBlazor/Components/DatePicker/MudDateRangePicker.razor @@ -34,7 +34,7 @@ PlaceholderStart="@PlaceholderStart" PlaceholderEnd="@PlaceholderEnd" SeparatorIcon="@SeparatorIcon" - Clearable="Clearable" + Clearable="@(Clearable && !GetReadOnlyState())" Underline="@Underline" /> ; diff --git a/src/MudBlazor/Components/Drawer/MudDrawer.razor.cs b/src/MudBlazor/Components/Drawer/MudDrawer.razor.cs index 404ea1ee48cf..8d073b5eb596 100644 --- a/src/MudBlazor/Components/Drawer/MudDrawer.razor.cs +++ b/src/MudBlazor/Components/Drawer/MudDrawer.razor.cs @@ -206,7 +206,12 @@ public MudDrawer() /// : Aliases to /// : Aliases to /// - /// Setting the value to will always close the drawer, while will always keep it open. + /// + /// Setting the value to will always close the drawer, while will always keep it open. + /// + /// + /// Applies when is set to or . + /// /// [Parameter] [Category(CategoryTypes.Drawer.Behavior)] @@ -454,6 +459,11 @@ async Task IBrowserViewportObserver.NotifyBrowserViewportChangeAsync(BrowserView if (browserViewportEventArgs.IsImmediate) { _lastUpdatedBreakpoint = browserViewportEventArgs.Breakpoint; + if (!IsResponsiveOrMini()) + { + return; + } + if (HandleBreakpointNone()) { await InitialOpenState(false); diff --git a/src/MudBlazor/Components/DropZone/MudDropContainer.razor.cs b/src/MudBlazor/Components/DropZone/MudDropContainer.razor.cs index 3deecd6a327d..224bf5110dd7 100644 --- a/src/MudBlazor/Components/DropZone/MudDropContainer.razor.cs +++ b/src/MudBlazor/Components/DropZone/MudDropContainer.razor.cs @@ -24,9 +24,9 @@ public partial class MudDropContainer : MudComponentBase where T : notnull private Dictionary> _mudDropZones = new(); protected string Classname => - new CssBuilder("mud-drop-container") - .AddClass(Class) - .Build(); + new CssBuilder("mud-drop-container") + .AddClass(Class) + .Build(); /// /// The content within this container. diff --git a/src/MudBlazor/Components/DropZone/MudDynamicDropItem.razor.cs b/src/MudBlazor/Components/DropZone/MudDynamicDropItem.razor.cs index 6dca40854a83..d92beb86dbdb 100644 --- a/src/MudBlazor/Components/DropZone/MudDynamicDropItem.razor.cs +++ b/src/MudBlazor/Components/DropZone/MudDynamicDropItem.razor.cs @@ -272,9 +272,9 @@ private void HandleDragLeave() #endregion protected string Classname => - new CssBuilder("mud-drop-item") - .AddClass(DraggingClass, _dragOperationIsInProgress) - .AddClass(DisabledClass, Disabled) - .AddClass(Class) - .Build(); + new CssBuilder("mud-drop-item") + .AddClass(DraggingClass, _dragOperationIsInProgress) + .AddClass(DisabledClass, Disabled) + .AddClass(Class) + .Build(); } diff --git a/src/MudBlazor/Components/Form/MudForm.razor.cs b/src/MudBlazor/Components/Form/MudForm.razor.cs index 08e979752d5a..1e7139631fe5 100644 --- a/src/MudBlazor/Components/Form/MudForm.razor.cs +++ b/src/MudBlazor/Components/Form/MudForm.razor.cs @@ -17,12 +17,12 @@ public partial class MudForm : MudComponentBase, IDisposable, IForm { protected string Classname => new CssBuilder("mud-form") - .AddClass($"gap-{Spacing}", Spacing >= 0) - .AddClass(Class) - .Build(); + .AddClass($"gap-{Spacing}", Spacing >= 0) + .AddClass(Class) + .Build(); /// - /// The content within this form.. + /// The content within this form. /// [Parameter] [Category(CategoryTypes.Form.ValidatedData)] diff --git a/src/MudBlazor/Components/Input/MudInput.razor b/src/MudBlazor/Components/Input/MudInput.razor index dc433864349b..fbb8b3085537 100644 --- a/src/MudBlazor/Components/Input/MudInput.razor +++ b/src/MudBlazor/Components/Input/MudInput.razor @@ -105,7 +105,7 @@ } } - @if (GetClearable() && !GetDisabledState()) + @if (ShowClearButton()) { : MudBaseInput protected string Classname => new CssBuilder( - MudInputCssHelper.GetClassname(this, - () => HasNativeHtmlPlaceholder() || - !string.IsNullOrEmpty(Text) || - Adornment == Adornment.Start || - !string.IsNullOrWhiteSpace(Placeholder) || - ShrinkLabel)) - .AddClass("mud-input-auto-grow", () => AutoGrow) - .Build(); + MudInputCssHelper.GetClassname(this, + () => HasNativeHtmlPlaceholder() || + !string.IsNullOrEmpty(Text) || + Adornment == Adornment.Start || + !string.IsNullOrWhiteSpace(Placeholder) || + ShrinkLabel)) + .AddClass("mud-input-auto-grow", () => AutoGrow) + .Build(); protected string InputClassname => MudInputCssHelper.GetInputClassname(this); @@ -37,7 +37,7 @@ public partial class MudInput : MudBaseInput .AddClass("mud-icon-button-edge-end", Adornment == Adornment.End && HideSpinButtons) .AddClass("me-6", Adornment != Adornment.End && HideSpinButtons == false) .AddClass("mud-icon-button-edge-margin-end", Adornment != Adornment.End && HideSpinButtons) - .Build(); + .Build(); /// /// The type of input collected by this component. @@ -224,15 +224,27 @@ public override ValueTask SelectRangeAsync(int pos1, int pos2) private Size GetButtonSize() => Margin == Margin.Dense ? Size.Small : Size.Medium; /// - /// If true, Clearable is true and there is a non null value (non-string for string values) + /// Determine whether to show the clear button when Clearable==true. + /// Of course the clear button won't show up if the text field is empty /// - private bool GetClearable() + private bool ShowClearButton() { + if (GetDisabledState()) + { + return false; + } + if (!Clearable) { return false; } + // If this is a standalone input it will not be clearable when read-only + if (SubscribeToParentForm && GetReadOnlyState()) + { + return false; + } + if (Value is string stringValue) { return !string.IsNullOrWhiteSpace(stringValue); diff --git a/src/MudBlazor/Components/Input/MudRangeInput.razor b/src/MudBlazor/Components/Input/MudRangeInput.razor index 0d42d19d14dd..f6bcad847e83 100644 --- a/src/MudBlazor/Components/Input/MudRangeInput.razor +++ b/src/MudBlazor/Components/Input/MudRangeInput.razor @@ -61,7 +61,7 @@ @if (IsClearable() && !GetDisabledState()) { - MudInputCssHelper.GetAdornmentClassname(this); + protected string ClearButtonClassname => + new CssBuilder("mud-input-clear-button") + .AddClass(Adornment is Adornment.Start ? "me-0" : "me-n4") + .Build(); + /// /// The hint displayed before the user enters a starting value. /// diff --git a/src/MudBlazor/Components/Mask/MudMask.razor b/src/MudBlazor/Components/Mask/MudMask.razor index 27b376367e79..ffb04326e08d 100644 --- a/src/MudBlazor/Components/Mask/MudMask.razor +++ b/src/MudBlazor/Components/Mask/MudMask.razor @@ -85,7 +85,7 @@ } - @if (_showClearable && !GetDisabledState()) + @if (ShowClearButton()) { .AddClass("mud-ltr", GetInputType() == InputType.Email || GetInputType() == InputType.Telephone) .AddClass($"mud-typography-{Typo.ToDescriptionString()}") .AddClass(Class) - .Build(); + .Build(); protected string InputClassname => new CssBuilder("mud-input-slot") @@ -47,7 +47,7 @@ public partial class MudMask : MudBaseInput .AddClass($"mud-input-root-adorned-{Adornment.ToDescriptionString()}", Adornment != Adornment.None) .AddClass($"mud-input-root-margin-{Margin.ToDescriptionString()}", () => Margin != Margin.None) .AddClass(Class) - .Build(); + .Build(); protected string AdornmentClassname => new CssBuilder() @@ -55,7 +55,7 @@ public partial class MudMask : MudBaseInput .AddClass($"mud-text", !string.IsNullOrEmpty(AdornmentText)) .AddClass($"mud-input-root-filled-shrink", Variant == Variant.Filled) .AddClass(Class) - .Build(); + .Build(); protected string ClearButtonClassname => new CssBuilder("mud-input-clear-button") @@ -63,7 +63,7 @@ public partial class MudMask : MudBaseInput .AddClass("mud-icon-button-edge-end", Adornment == Adornment.End) // .AddClass("me-6", Adornment != Adornment.End && HideSpinButtons == false) .AddClass("mud-icon-button-edge-margin-end", Adornment != Adornment.End) - .Build(); + .Build(); [Inject] private IKeyInterceptorService KeyInterceptorService { get; set; } = null!; @@ -120,7 +120,10 @@ private void UpdateClearable(object value) var showClearable = Clearable && !string.IsNullOrWhiteSpace(Text); if (_showClearable != showClearable) + { _showClearable = showClearable; + StateHasChanged(); + } } /// @@ -146,7 +149,6 @@ protected override async Task OnInitializedAsync() { if (Text != Mask.Text) await SetTextAsync(Mask.Text, updateValue: false); - await base.OnInitializedAsync(); } @@ -308,6 +310,13 @@ private string GetCounterText() => Counter == null ? (string.IsNullOrEmpty(Text) ? "0" : $"{Text.Length}") : ((string.IsNullOrEmpty(Text) ? "0" : $"{Text.Length}") + $" / {Counter}")); + private bool ShowClearButton() + { + if (SubscribeToParentForm) + return _showClearable && !GetReadOnlyState() && !GetDisabledState(); + return _showClearable && !GetDisabledState(); + } + /// /// Clears the text and value for this input. /// diff --git a/src/MudBlazor/Components/Menu/MudMenu.razor.cs b/src/MudBlazor/Components/Menu/MudMenu.razor.cs index 7620a2a63696..9eb1f53d0d8f 100644 --- a/src/MudBlazor/Components/Menu/MudMenu.razor.cs +++ b/src/MudBlazor/Components/Menu/MudMenu.razor.cs @@ -196,11 +196,11 @@ public partial class MudMenu : MudComponentBase, IActivatable /// The point where the menu will open from. /// /// - /// Defaults to . + /// Defaults to . /// [Parameter] [Category(CategoryTypes.Menu.PopupAppearance)] - public Origin AnchorOrigin { get; set; } = Origin.TopLeft; + public Origin AnchorOrigin { get; set; } = Origin.BottomLeft; /// /// Sets the direction the menu will open from the anchor. diff --git a/src/MudBlazor/Components/NumericField/MudNumericField.razor b/src/MudBlazor/Components/NumericField/MudNumericField.razor index 68e135f80ee3..58c014ca1407 100644 --- a/src/MudBlazor/Components/NumericField/MudNumericField.razor +++ b/src/MudBlazor/Components/NumericField/MudNumericField.razor @@ -62,7 +62,7 @@ OnIncrement="@Increment" OnDecrement="@Decrement" OnMouseWheel="@OnMouseWheelAsync" - Clearable="@Clearable" + Clearable="@(Clearable && !GetReadOnlyState())" ClearIcon="@ClearIcon" ShrinkLabel="@ShrinkLabel" InputId="@InputElementId" diff --git a/src/MudBlazor/Components/Picker/MudPicker.razor b/src/MudBlazor/Components/Picker/MudPicker.razor index 4492d31edd7b..44310b4b41e9 100644 --- a/src/MudBlazor/Components/Picker/MudPicker.razor +++ b/src/MudBlazor/Components/Picker/MudPicker.razor @@ -33,7 +33,7 @@ RequiredError="@RequiredError" Error="@Error" ErrorText="@ErrorText" - Clearable="@(GetReadOnlyState() ? false : Clearable)" + Clearable="@(Clearable && !GetReadOnlyState())" OnClearButtonClick="@(async () => await ClearAsync())" @onclick="OnClickAsync" />; diff --git a/src/MudBlazor/Components/Picker/MudPicker.razor.cs b/src/MudBlazor/Components/Picker/MudPicker.razor.cs index 391db5c38b39..d6af476658f1 100644 --- a/src/MudBlazor/Components/Picker/MudPicker.razor.cs +++ b/src/MudBlazor/Components/Picker/MudPicker.razor.cs @@ -406,11 +406,11 @@ public IMask Mask /// The location the popover opens, relative to its container. /// /// - /// Defaults to . + /// Defaults to . /// [Parameter] [Category(CategoryTypes.Popover.Appearance)] - public Origin AnchorOrigin { get; set; } = Origin.TopLeft; + public Origin AnchorOrigin { get; set; } = Origin.BottomLeft; /// /// The direction the popover opens, relative to its container. diff --git a/src/MudBlazor/Components/Select/MudSelect.razor b/src/MudBlazor/Components/Select/MudSelect.razor index 244e7c604b09..4a5e342abc8c 100644 --- a/src/MudBlazor/Components/Select/MudSelect.razor +++ b/src/MudBlazor/Components/Select/MudSelect.razor @@ -45,7 +45,7 @@ IconSize="@IconSize" AdornmentAriaLabel="@AdornmentAriaLabel" OnAdornmentClick="@OnAdornmentClick" - Clearable="@Clearable" + Clearable="@(Clearable && !GetReadOnlyState())" ClearIcon="@ClearIcon" OnClearButtonClick="@(async (e) => await SelectClearButtonClickHandlerAsync(e))" @attributes="UserAttributes" diff --git a/src/MudBlazor/Components/Select/MudSelect.razor.cs b/src/MudBlazor/Components/Select/MudSelect.razor.cs index 50ad965c31e5..82a8c7713e21 100644 --- a/src/MudBlazor/Components/Select/MudSelect.razor.cs +++ b/src/MudBlazor/Components/Select/MudSelect.razor.cs @@ -499,18 +499,18 @@ internal void Remove(MudSelectItem item) public int MaxHeight { get; set; } = 300; /// - /// Set the anchor origin point to determen where the popover will open from. + /// Set the anchor origin point to determine where the popover will open from. /// [Parameter] [Category(CategoryTypes.FormComponent.ListAppearance)] - public Origin AnchorOrigin { get; set; } = Origin.TopCenter; + public Origin AnchorOrigin { get; set; } = Origin.BottomLeft; /// /// Sets the transform origin point for the popover. /// [Parameter] [Category(CategoryTypes.FormComponent.ListAppearance)] - public Origin TransformOrigin { get; set; } = Origin.TopCenter; + public Origin TransformOrigin { get; set; } = Origin.TopLeft; /// /// If true, the Select's input will not show any values that are not defined in the dropdown. diff --git a/src/MudBlazor/Components/Stepper/MudStepper.razor b/src/MudBlazor/Components/Stepper/MudStepper.razor index 172efd6c333c..03b908b09b04 100644 --- a/src/MudBlazor/Components/Stepper/MudStepper.razor +++ b/src/MudBlazor/Components/Stepper/MudStepper.razor @@ -1,4 +1,5 @@ @namespace MudBlazor +@using MudBlazor.Resources @using MudBlazor.Utilities @inherits MudComponentBase @@ -65,7 +66,7 @@ { @* Reset Button *@ - @Localizer["MudStepper_Reset"] + @Localizer[LanguageResource.MudStepper_Reset] } @@ -73,7 +74,7 @@ { @* Previous Button *@ - @Localizer["MudStepper_Previous"] + @Localizer[LanguageResource.MudStepper_Previous] } @@ -85,21 +86,21 @@ { @* Skip Button *@ - @Localizer["MudStepper_Skip"] + @Localizer[LanguageResource.MudStepper_Skip] } @if (ShowCompleteInsteadOfNext) { @* Complete Button *@ - @Localizer["MudStepper_Complete"] + @Localizer[LanguageResource.MudStepper_Complete] } else { @* Next Button *@ - @Localizer["MudStepper_Next"] + @Localizer[LanguageResource.MudStepper_Next] } } diff --git a/src/MudBlazor/Components/Stepper/MudStepper.razor.cs b/src/MudBlazor/Components/Stepper/MudStepper.razor.cs index 7cc92647de4a..18f30fa26efe 100644 --- a/src/MudBlazor/Components/Stepper/MudStepper.razor.cs +++ b/src/MudBlazor/Components/Stepper/MudStepper.razor.cs @@ -27,22 +27,22 @@ public MudStepper() protected string Classname => new CssBuilder("mud-stepper") - .AddClass("mud-stepper__horizontal", Vertical == false) - .AddClass("mud-stepper__vertical", Vertical) - .AddClass("mud-stepper__center-labels", CenterLabels && !Vertical) - .AddClass(Class) - .Build(); + .AddClass("mud-stepper__horizontal", Vertical == false) + .AddClass("mud-stepper__vertical", Vertical) + .AddClass("mud-stepper__center-labels", CenterLabels && !Vertical) + .AddClass(Class) + .Build(); internal string StepClassname => new CssBuilder("mud-stepper-content") - .AddClass(StepClass) - .Build(); + .AddClass(StepClass) + .Build(); protected string NavClassname => new CssBuilder("mud-stepper-nav") - .AddClass("mud-stepper-nav-scrollable", ScrollableNavigation) - .AddClass(NavClass) - .Build(); + .AddClass("mud-stepper-nav-scrollable", ScrollableNavigation) + .AddClass(NavClass) + .Build(); /// /// The steps that have been defined in razor. diff --git a/src/MudBlazor/Components/Tabs/MudTabs.razor.cs b/src/MudBlazor/Components/Tabs/MudTabs.razor.cs index 228673b7a690..1d58ef7ca724 100644 --- a/src/MudBlazor/Components/Tabs/MudTabs.razor.cs +++ b/src/MudBlazor/Components/Tabs/MudTabs.razor.cs @@ -473,77 +473,79 @@ private async void ActivatePanel(MudTabPanel panel, MouseEventArgs? ev, bool ign #endregion #region Style and classes + protected string TabsClassnames => new CssBuilder("mud-tabs") - .AddClass($"mud-tabs-rounded", ApplyEffectsToContainer && Rounded) - .AddClass($"mud-paper-outlined", ApplyEffectsToContainer && Outlined) - .AddClass($"mud-elevation-{Elevation}", ApplyEffectsToContainer && Elevation != 0) - .AddClass($"mud-tabs-reverse", Position == Position.Bottom) - .AddClass($"mud-tabs-vertical", IsVerticalTabs()) - .AddClass($"mud-tabs-vertical-reverse", Position == Position.Right && !RightToLeft || (Position == Position.Left) && RightToLeft || Position == Position.End) - .AddClass(InternalClassName) - .AddClass(Class) - .Build(); + .AddClass($"mud-tabs-rounded", ApplyEffectsToContainer && Rounded) + .AddClass($"mud-paper-outlined", ApplyEffectsToContainer && Outlined) + .AddClass($"mud-elevation-{Elevation}", ApplyEffectsToContainer && Elevation != 0) + .AddClass($"mud-tabs-reverse", Position == Position.Bottom) + .AddClass($"mud-tabs-vertical", IsVerticalTabs()) + .AddClass($"mud-tabs-vertical-reverse", Position == Position.Right && !RightToLeft || (Position == Position.Left) && RightToLeft || Position == Position.End) + .AddClass(InternalClassName) + .AddClass(Class) + .Build(); protected string TabBarClassnames => new CssBuilder("mud-tabs-tabbar") - .AddClass($"mud-tabs-rounded", !ApplyEffectsToContainer && Rounded) - .AddClass($"mud-tabs-vertical", IsVerticalTabs()) - .AddClass($"mud-tabs-tabbar-{Color.ToDescriptionString()}", Color != Color.Default) - .AddClass($"mud-tabs-border-{ConvertPosition(Position).ToDescriptionString()}", Border) - .AddClass($"mud-paper-outlined", !ApplyEffectsToContainer && Outlined) - .AddClass($"mud-elevation-{Elevation}", !ApplyEffectsToContainer && Elevation != 0) - .AddClass(TabHeaderClass) - .Build(); + .AddClass($"mud-tabs-rounded", !ApplyEffectsToContainer && Rounded) + .AddClass($"mud-tabs-vertical", IsVerticalTabs()) + .AddClass($"mud-tabs-tabbar-{Color.ToDescriptionString()}", Color != Color.Default) + .AddClass($"mud-tabs-border-{ConvertPosition(Position).ToDescriptionString()}", Border) + .AddClass($"mud-paper-outlined", !ApplyEffectsToContainer && Outlined) + .AddClass($"mud-elevation-{Elevation}", !ApplyEffectsToContainer && Elevation != 0) + .AddClass(TabHeaderClass) + .Build(); protected string WrapperClassnames => new CssBuilder("mud-tabs-tabbar-wrapper") - .AddClass($"mud-tabs-centered", Centered) - .AddClass($"mud-tabs-vertical", IsVerticalTabs()) - .Build(); + .AddClass($"mud-tabs-centered", Centered) + .AddClass($"mud-tabs-vertical", IsVerticalTabs()) + .Build(); protected string WrapperScrollStyle => - new StyleBuilder() - .AddStyle("transform", $"translateX({(-1 * _scrollPosition).ToString(CultureInfo.InvariantCulture)}px)", Position is Position.Top or Position.Bottom) - .AddStyle("transform", $"translateY({(-1 * _scrollPosition).ToString(CultureInfo.InvariantCulture)}px)", IsVerticalTabs()) - .Build(); + new StyleBuilder() + .AddStyle("transform", $"translateX({(-1 * _scrollPosition).ToString(CultureInfo.InvariantCulture)}px)", Position is Position.Top or Position.Bottom) + .AddStyle("transform", $"translateY({(-1 * _scrollPosition).ToString(CultureInfo.InvariantCulture)}px)", IsVerticalTabs()) + .Build(); protected string PanelsClassnames => new CssBuilder("mud-tabs-panels") - .AddClass($"mud-tabs-vertical", IsVerticalTabs()) - .AddClass(PanelClass) - .Build(); + .AddClass($"mud-tabs-vertical", IsVerticalTabs()) + .AddClass(PanelClass) + .Build(); protected string SliderClass => new CssBuilder("mud-tab-slider") - .AddClass($"mud-{SliderColor.ToDescriptionString()}", SliderColor != Color.Inherit) - .AddClass($"mud-tab-slider-horizontal", Position is Position.Top or Position.Bottom) - .AddClass($"mud-tab-slider-vertical", IsVerticalTabs()) - .AddClass($"mud-tab-slider-horizontal-reverse", Position == Position.Bottom) - .AddClass($"mud-tab-slider-vertical-reverse", Position == Position.Right || Position == Position.Start && RightToLeft || Position == Position.End && !RightToLeft) - .Build(); + .AddClass($"mud-{SliderColor.ToDescriptionString()}", SliderColor != Color.Inherit) + .AddClass($"mud-tab-slider-horizontal", Position is Position.Top or Position.Bottom) + .AddClass($"mud-tab-slider-vertical", IsVerticalTabs()) + .AddClass($"mud-tab-slider-horizontal-reverse", Position == Position.Bottom) + .AddClass($"mud-tab-slider-vertical-reverse", Position == Position.Right || Position == Position.Start && RightToLeft || Position == Position.End && !RightToLeft) + .Build(); protected string MaxHeightStyles => new StyleBuilder() - .AddStyle("max-height", MaxHeight.ToPx(), MaxHeight != null) - .Build(); - - protected string SliderStyle => RightToLeft ? - new StyleBuilder() - .AddStyle("width", _sliderSize.ToPx(), Position is Position.Top or Position.Bottom) - .AddStyle("right", _sliderPosition.ToPx(), Position is Position.Top or Position.Bottom) - .AddStyle("transition", SliderAnimation ? "right .3s cubic-bezier(.64,.09,.08,1);" : "none", Position is Position.Top or Position.Bottom) - .AddStyle("transition", SliderAnimation ? "top .3s cubic-bezier(.64,.09,.08,1);" : "none", IsVerticalTabs()) - .AddStyle("height", _sliderSize.ToPx(), IsVerticalTabs()) - .AddStyle("top", _sliderPosition.ToPx(), IsVerticalTabs()) - .Build() : new StyleBuilder() - .AddStyle("width", _sliderSize.ToPx(), Position is Position.Top or Position.Bottom) - .AddStyle("left", _sliderPosition.ToPx(), Position is Position.Top or Position.Bottom) - .AddStyle("transition", SliderAnimation ? "left .3s cubic-bezier(.64,.09,.08,1);" : "none", Position is Position.Top or Position.Bottom) - .AddStyle("transition", SliderAnimation ? "top .3s cubic-bezier(.64,.09,.08,1);" : "none", IsVerticalTabs()) - .AddStyle("height", _sliderSize.ToPx(), IsVerticalTabs()) - .AddStyle("top", _sliderPosition.ToPx(), IsVerticalTabs()) - .Build(); + .AddStyle("max-height", MaxHeight.ToPx(), MaxHeight != null) + .Build(); + + protected string SliderStyle => RightToLeft + ? new StyleBuilder() + .AddStyle("width", _sliderSize.ToPx(), Position is Position.Top or Position.Bottom) + .AddStyle("right", _sliderPosition.ToPx(), Position is Position.Top or Position.Bottom) + .AddStyle("transition", SliderAnimation ? "right .3s cubic-bezier(.64,.09,.08,1);" : "none", Position is Position.Top or Position.Bottom) + .AddStyle("transition", SliderAnimation ? "top .3s cubic-bezier(.64,.09,.08,1);" : "none", IsVerticalTabs()) + .AddStyle("height", _sliderSize.ToPx(), IsVerticalTabs()) + .AddStyle("top", _sliderPosition.ToPx(), IsVerticalTabs()) + .Build() + : new StyleBuilder() + .AddStyle("width", _sliderSize.ToPx(), Position is Position.Top or Position.Bottom) + .AddStyle("left", _sliderPosition.ToPx(), Position is Position.Top or Position.Bottom) + .AddStyle("transition", SliderAnimation ? "left .3s cubic-bezier(.64,.09,.08,1);" : "none", Position is Position.Top or Position.Bottom) + .AddStyle("transition", SliderAnimation ? "top .3s cubic-bezier(.64,.09,.08,1);" : "none", IsVerticalTabs()) + .AddStyle("height", _sliderSize.ToPx(), IsVerticalTabs()) + .AddStyle("top", _sliderPosition.ToPx(), IsVerticalTabs()) + .Build(); private bool IsVerticalTabs() { diff --git a/src/MudBlazor/Components/TextField/MudTextField.razor b/src/MudBlazor/Components/TextField/MudTextField.razor index 9fffb88333d7..42ce0e384a63 100644 --- a/src/MudBlazor/Components/TextField/MudTextField.razor +++ b/src/MudBlazor/Components/TextField/MudTextField.razor @@ -62,7 +62,7 @@ KeyDownPreventDefault="KeyDownPreventDefault" KeyUpPreventDefault="KeyUpPreventDefault" HideSpinButtons="true" - Clearable="@Clearable" + Clearable="@ShowClearButton()" ClearIcon="@ClearIcon" OnClearButtonClick="@OnClearButtonClick" Pattern="@Pattern" @@ -103,7 +103,7 @@ HelperText="@HelperText" Immediate="@Immediate" Margin="@Margin" OnBlur="@OnBlurredAsync" - Clearable="@Clearable" + Clearable="@ShowClearButton()" ClearIcon="@ClearIcon" OnClearButtonClick="@OnClearButtonClick" InputId="@InputElementId" diff --git a/src/MudBlazor/Components/TextField/MudTextField.razor.cs b/src/MudBlazor/Components/TextField/MudTextField.razor.cs index 2acff8c7e872..e8df47d88183 100644 --- a/src/MudBlazor/Components/TextField/MudTextField.razor.cs +++ b/src/MudBlazor/Components/TextField/MudTextField.razor.cs @@ -217,6 +217,13 @@ protected override Task SetTextAsync(string? text, bool updateValue = true) internal override InputType GetInputType() => InputType; + private bool ShowClearButton() + { + if (SubscribeToParentForm) + return Clearable && !GetReadOnlyState() && !GetDisabledState(); + return Clearable && !GetDisabledState(); + } + private Task OnMaskedValueChanged(string s) => SetTextAsync(s); private string GetCounterText() => Counter switch diff --git a/src/MudBlazor/Components/Toggle/MudToggleGroup.razor.cs b/src/MudBlazor/Components/Toggle/MudToggleGroup.razor.cs index 3c491f2001d0..a01d299e8b13 100644 --- a/src/MudBlazor/Components/Toggle/MudToggleGroup.razor.cs +++ b/src/MudBlazor/Components/Toggle/MudToggleGroup.razor.cs @@ -229,6 +229,14 @@ protected internal void Register(MudToggleItem item) StateHasChanged(); } + protected internal void Unregister(MudToggleItem item) + { + if (_items.Remove(item)) + { + StateHasChanged(); + } + } + protected override void OnInitialized() { base.OnInitialized(); diff --git a/src/MudBlazor/Components/Toggle/MudToggleItem.razor.cs b/src/MudBlazor/Components/Toggle/MudToggleItem.razor.cs index f892a01d8e6f..ac6b2ec5af7e 100644 --- a/src/MudBlazor/Components/Toggle/MudToggleItem.razor.cs +++ b/src/MudBlazor/Components/Toggle/MudToggleItem.razor.cs @@ -8,7 +8,7 @@ namespace MudBlazor { #nullable enable - public partial class MudToggleItem : MudComponentBase + public partial class MudToggleItem : MudComponentBase, IDisposable { protected string Classname => new CssBuilder("mud-toggle-item") .AddClass(Parent?.SelectedClass, Selected && !string.IsNullOrEmpty(Parent?.SelectedClass)) @@ -85,15 +85,13 @@ public partial class MudToggleItem : MudComponentBase { return SelectedIcon; } - else - { - if (UnselectedIcon is null && Parent?.FixedContent == true) - { - return Icons.Custom.Uncategorized.Empty; - } - return UnselectedIcon; + if (UnselectedIcon is null && Parent?.FixedContent == true) + { + return Icons.Custom.Uncategorized.Empty; } + + return UnselectedIcon; } protected override void OnInitialized() @@ -102,6 +100,20 @@ protected override void OnInitialized() Parent?.Register(this); } + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + Parent?.Unregister(this); + } + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + public void SetSelected(bool selected) { Selected = selected; diff --git a/src/MudBlazor/Extensions/ServiceCollectionExtensions.cs b/src/MudBlazor/Extensions/ServiceCollectionExtensions.cs index 60b870a0673f..093e4adf3945 100644 --- a/src/MudBlazor/Extensions/ServiceCollectionExtensions.cs +++ b/src/MudBlazor/Extensions/ServiceCollectionExtensions.cs @@ -310,6 +310,7 @@ public static IServiceCollection AddMudLocalization(this IServiceCollection serv public static IServiceCollection AddMudServices(this IServiceCollection services) { return services + .AddCommonServices() .AddMudBlazorDialog() .AddMudBlazorSnackbar() .AddMudBlazorResizeListener() @@ -340,6 +341,7 @@ public static IServiceCollection AddMudServices(this IServiceCollection services configuration(options); return services + .AddCommonServices() .AddMudBlazorDialog() .AddMudBlazorSnackbar(snackBarConfiguration => { @@ -393,5 +395,12 @@ public static IServiceCollection AddMudServices(this IServiceCollection services .AddMudEventManager() .AddMudLocalization(); } + + private static IServiceCollection AddCommonServices(this IServiceCollection service) + { + service.TryAddSingleton(TimeProvider.System); + + return service; + } } } diff --git a/src/MudBlazor/Styles/components/_popover.scss b/src/MudBlazor/Styles/components/_popover.scss index 09aa9f5ddef5..e5e0a94ee1f2 100644 --- a/src/MudBlazor/Styles/components/_popover.scss +++ b/src/MudBlazor/Styles/components/_popover.scss @@ -25,6 +25,10 @@ } } +.mud-popover .mud-popover { + z-index: auto; // javascript will handle nested z-indexes +} + .mud-appbar { .mud-popover-cascading-value { z-index: calc(var(--mud-zindex-appbar) + 2); @@ -51,6 +55,13 @@ } } +.mud-select { + .mud-popover-cascading-value { + z-index: calc(var(--mud-zindex-select) + 5); + } + +} + .mud-popover { .mud-list { max-height: inherit; diff --git a/src/MudBlazor/TScripts/mudPopover.js b/src/MudBlazor/TScripts/mudPopover.js index 2ef6b9f28dee..356546d90e24 100644 --- a/src/MudBlazor/TScripts/mudPopover.js +++ b/src/MudBlazor/TScripts/mudPopover.js @@ -121,6 +121,11 @@ window.mudpopoverHelper = { flipMargin: 0, + basePopoverZIndex: parseInt(getComputedStyle(document.documentElement) + .getPropertyValue('--mud-zindex-popover')) || 1200, + + baseTooltipZIndex: parseInt(getComputedStyle(document.documentElement) + .getPropertyValue('--mud-zindex-tooltip')) || 1600, getPositionForFlippedPopver: function (inputArray, selector, boundingRect, selfRect) { const classList = []; for (var i = 0; i < inputArray.length; i++) { @@ -138,7 +143,9 @@ window.mudpopoverHelper = { }, placePopover: function (popoverNode, classSelector) { - + // parentNode is the calling element, mudmenu/tooltip/etc not the parent popover if it's a child popover + // this happens at page load unless it's popover inside a popover, then it happens when you activate the parent + if (popoverNode && popoverNode.parentNode) { const id = popoverNode.id.substr(8); const popoverContentNode = document.getElementById('popovercontent-' + id); @@ -171,7 +178,7 @@ window.mudpopoverHelper = { let top = postion.top; let offsetX = postion.offsetX; let offsetY = postion.offsetY; - + // flipping logic if (classList.contains('mud-popover-overflow-flip-onopen') || classList.contains('mud-popover-overflow-flip-always')) { const appBarElements = document.getElementsByClassName("mud-appbar mud-appbar-fixed-top"); @@ -257,16 +264,28 @@ window.mudpopoverHelper = { } else { // did not flip, ensure the left and top are inside bounds - if (left + offsetX < 0) { + // appbaroffset is another section + if (left + offsetX < 0 && // it's starting left of the screen + Math.abs(left + offsetX) < selfRect.width) { // it's not starting so far left the entire box would be hidden left = Math.max(0, left + offsetX); // set offsetX to 0 to avoid double offset offsetX = 0; } - if (top + offsetY < appBarOffset) { - top = Math.max(appBarOffset, top + offsetY); + + // will be covered by appbar so adjust zindex with appbar as parent + if (top + offsetY < appBarOffset && + appBarElements.length > 0) { + this.updatePopoverZIndex(popoverContentNode, appBarElements[0]); + //console.log(`top: ${top} | offsetY: ${offsetY} | total: ${top + offsetY} | appBarOffset: ${appBarOffset}`); + } + + if (top + offsetY < 0 && // it's starting above the screen + Math.abs(top + offsetY) < selfRect.height) { // it's not starting so far above the entire box would be hidden + top = Math.max(0, top + offsetY); // set offsetY to 0 to avoid double offset offsetY = 0; } + popoverContentNode.removeAttribute('data-mudpopover-flip'); } @@ -289,12 +308,19 @@ window.mudpopoverHelper = { popoverContentNode.style['left'] = (left + offsetX) + 'px'; popoverContentNode.style['top'] = (top + offsetY) + 'px'; + // update z-index by sending the calling popover to update z-index, + // and the parentnode of the calling popover (not content parent) + //console.log(popoverContentNode, popoverNode.parentNode); + this.updatePopoverZIndex(popoverContentNode, popoverNode.parentNode); if (window.getComputedStyle(popoverNode).getPropertyValue('z-index') != 'auto') { popoverContentNode.style['z-index'] = window.getComputedStyle(popoverNode).getPropertyValue('z-index'); popoverContentNode.skipZIndex = true; } } + else { + //console.log(`popoverNode: ${popoverNode} ${popoverNode ? popoverNode.parentNode : ""}`); + } }, placePopoverByClassSelector: function (classSelector = null) { @@ -314,7 +340,63 @@ window.mudpopoverHelper = { countProviders: function () { return document.querySelectorAll(".mud-popover-provider").length; - } + }, + + updatePopoverZIndex: function (popoverContentNode, parentNode) { + // find the first parent mud-popover if it exists + const parentPopover = parentNode.closest('.mud-popover'); + const parentOfPopover = popoverContentNode.parentNode; + // get --mud-zindex-popover from root + let newZIndex = window.mudpopoverHelper.basePopoverZIndex + 1; + const origZIndex = parseInt(popoverContentNode.style['z-index']) || 1; + const contentZIndex = popoverContentNode.style['z-index']; + // normal nested position update + if (parentPopover) { + // get parent popover z-index + const computedStyle = window.getComputedStyle(parentPopover); + const parentZIndexValue = computedStyle.getPropertyValue('z-index'); + if (parentZIndexValue !== 'auto') { + // parentpopovers will never be auto zindex due to css rules + // children are set "auto" z-index in css and therefore need updated + // set new z-index 1 above parent + newZIndex = parseInt(parentZIndexValue) + 1; + } + popoverContentNode.style['z-index'] = newZIndex; + } + // nested popover inside any other child element + else if (parentOfPopover) { + const computedStyle = window.getComputedStyle(parentOfPopover); + const tooltipZIndexValue = computedStyle.getPropertyValue('z-index'); + if (tooltipZIndexValue !== 'auto') { + newZIndex = parseInt(tooltipZIndexValue) + 1; + } + popoverContentNode.style['z-index'] = Math.max(newZIndex, window.mudpopoverHelper.baseTooltipZIndex + 1, origZIndex); + } + // tooltip container update + // (it's not technically a nested popover but when nested inside popover components it doesn't set zindex properly) + else if (parentNode && parentNode.classList.contains("mud-tooltip-root")) { + const computedStyle = window.getComputedStyle(parentNode); + const tooltipZIndexValue = computedStyle.getPropertyValue('z-index'); + if (tooltipZIndexValue !== 'auto') { + newZIndex = parseInt(tooltipZIndexValue) + 1; + } + popoverContentNode.style['z-index'] = Math.max(newZIndex, window.mudpopoverHelper.baseTooltipZIndex + 1); + } + // specific appbar interference update + else if (parentNode && parentNode.classList.contains("mud-appbar")) { + // adjust zindex to top of appbar if it's underneath + const computedStyle = window.getComputedStyle(parentNode); + const appBarZIndexValue = computedStyle.getPropertyValue('z-index'); + if (appBarZIndexValue !== 'auto') { + newZIndex = parseInt(appBarZIndexValue) + 1; + } + popoverContentNode.style['z-index'] = newZIndex; + } + // if popoverContentNode.style['z-index'] is not set or set lower than minimum set it to default popover zIndex + else if (!contentZIndex || parseInt(contentZIndex) < 1) { + popoverContentNode.style['z-index'] = newZIndex; + } + }, } class MudPopover { @@ -339,12 +421,13 @@ class MudPopover { window.mudpopoverHelper.placePopoverByNode(target); } else if (mutation.attributeName == 'data-ticks') { + // data-ticks are important for Direction and Location, it doesn't reposition + // if they aren't there const tickAttribute = target.getAttribute('data-ticks'); - const parent = target.parentElement; const tickValues = []; let max = -1; - if (parent) { + if (parent && parent.children) { for (let i = 0; i < parent.children.length; i++) { const childNode = parent.children[i]; const tickValue = parseInt(childNode.getAttribute('data-ticks')); @@ -369,7 +452,8 @@ class MudPopover { } const sortedTickValues = tickValues.sort((x, y) => x - y); - + // z-index calculation not used here + continue; for (let i = 0; i < parent.children.length; i++) { const childNode = parent.children[i]; const tickValue = parseInt(childNode.getAttribute('data-ticks')); @@ -380,8 +464,8 @@ class MudPopover { if (childNode.skipZIndex == true) { continue; } - - childNode.style['z-index'] = 'calc(var(--mud-zindex-popover) + ' + (sortedTickValues.indexOf(tickValue) + 3).toString() + ')'; + const newIndex = window.mudpopoverHelper.basePopoverZIndex + sortedTickValues.indexOf(tickValue) + 3; + childNode.style['z-index'] = newIndex; } } } diff --git a/src/MudBlazor/Utilities/CodeMessage.cs b/src/MudBlazor/Utilities/CodeMessage.cs deleted file mode 100644 index 7a802812231e..000000000000 --- a/src/MudBlazor/Utilities/CodeMessage.cs +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright (c) MudBlazor 2021 -// MudBlazor licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -namespace MudBlazor.Utilities -{ - internal class CodeMessage - { - internal const string SerializationUnreferencedCodeMessage = "Serialization and deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved. If you sure that your type is preserved use UnconditionalSuppressMessage to ignore error."; - } -}