From ee26ae48ddfb0856a68f470622b9cffcb9fb69a8 Mon Sep 17 00:00:00 2001 From: Redth Date: Fri, 17 Apr 2026 14:20:03 -0400 Subject: [PATCH] Add MAUI SemanticProperties to inspector properties panel Add a new 'Accessibility' group to the Visual Tree inspector's properties panel that queries and displays MAUI's SemanticProperties attached properties: - SemanticProperties.Description (text editor) - SemanticProperties.Hint (text editor) - SemanticProperties.HeadingLevel (enum: None, Level1-Level9) Also enrich DevFlowElementInfo model with optional semantic fields (semanticDescription, semanticHint, semanticHeadingLevel) so agents can include them in tree data. When present, these are shown in a dedicated Accessibility section in the Element identity panel. Properties gracefully degrade - they only appear when the agent returns non-null values. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../Models/DevFlow/DevFlowModels.cs | 9 ++++ .../Pages/Inspector/DevFlowTreeTab.razor | 42 ++++++++++++++++++- 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/src/MauiSherpa.Core/Models/DevFlow/DevFlowModels.cs b/src/MauiSherpa.Core/Models/DevFlow/DevFlowModels.cs index 70604f5..600349a 100644 --- a/src/MauiSherpa.Core/Models/DevFlow/DevFlowModels.cs +++ b/src/MauiSherpa.Core/Models/DevFlow/DevFlowModels.cs @@ -389,6 +389,15 @@ public class DevFlowElementInfo [JsonPropertyName("nativeProperties")] public Dictionary? NativeProperties { get; set; } + [JsonPropertyName("semanticDescription")] + public string? SemanticDescription { get; set; } + + [JsonPropertyName("semanticHint")] + public string? SemanticHint { get; set; } + + [JsonPropertyName("semanticHeadingLevel")] + public string? SemanticHeadingLevel { get; set; } + [JsonPropertyName("children")] public List? Children { get; set; } } diff --git a/src/MauiSherpa/Pages/Inspector/DevFlowTreeTab.razor b/src/MauiSherpa/Pages/Inspector/DevFlowTreeTab.razor index e5e4f1f..683482b 100644 --- a/src/MauiSherpa/Pages/Inspector/DevFlowTreeTab.razor +++ b/src/MauiSherpa/Pages/Inspector/DevFlowTreeTab.razor @@ -165,6 +165,35 @@ } + + @if (!string.IsNullOrEmpty(selectedElement.SemanticDescription) || !string.IsNullOrEmpty(selectedElement.SemanticHint) || !string.IsNullOrEmpty(selectedElement.SemanticHeadingLevel)) + { +
+
Accessibility
+ @if (!string.IsNullOrEmpty(selectedElement.SemanticDescription)) + { +
+ Description + @selectedElement.SemanticDescription +
+ } + @if (!string.IsNullOrEmpty(selectedElement.SemanticHint)) + { +
+ Hint + @selectedElement.SemanticHint +
+ } + @if (!string.IsNullOrEmpty(selectedElement.SemanticHeadingLevel) && !selectedElement.SemanticHeadingLevel.Equals("None", StringComparison.OrdinalIgnoreCase)) + { +
+ Heading Level + @selectedElement.SemanticHeadingLevel +
+ } +
+ } + @if (selectedElement.Gestures?.Count > 0) { @@ -380,11 +409,17 @@ EnumValues: new[] { "Default", "Chat", "Email", "Numeric", "Plain", "Telephone", "Text", "Url" }), ["AutomationId"] = new(EditorType.Text, "Behavior", SortOrder: 0), ["Text"] = new(EditorType.Text, "Appearance", SortOrder: 0), + + // --- Accessibility (SemanticProperties) --- + ["SemanticProperties.Description"] = new(EditorType.Text, "Accessibility", SortOrder: 0), + ["SemanticProperties.Hint"] = new(EditorType.Text, "Accessibility", SortOrder: 1), + ["SemanticProperties.HeadingLevel"] = new(EditorType.Enum, "Accessibility", SortOrder: 2, + EnumValues: new[] { "None", "Level1", "Level2", "Level3", "Level4", "Level5", "Level6", "Level7", "Level8", "Level9" }), }; private static readonly string[] CommonProperties = PropertyRegistry.Keys.ToArray(); - private static readonly string[] GroupOrder = new[] { "Appearance", "Layout", "Behavior", "Transform", "Other" }; + private static readonly string[] GroupOrder = new[] { "Appearance", "Layout", "Behavior", "Accessibility", "Transform", "Other" }; private static PropertyMeta GetMeta(string propName) => PropertyRegistry.TryGetValue(propName, out var meta) ? meta : new PropertyMeta(EditorType.Text, "Other"); @@ -2859,6 +2894,11 @@ letter-spacing: 0.04em; } + .prop-group-icon { + margin-right: 0.25rem; + font-size: 0.65rem; + } + /* Boolean toggle */ .bool-toggle { display: flex;