diff --git a/plugins/reactor/skills/reactor-dsl/references/reactor.api.txt b/plugins/reactor/skills/reactor-dsl/references/reactor.api.txt index 8bc228124..216b25be6 100644 --- a/plugins/reactor/skills/reactor-dsl/references/reactor.api.txt +++ b/plugins/reactor/skills/reactor-dsl/references/reactor.api.txt @@ -608,6 +608,7 @@ T.Immediate() → T T.InteractionStates(Func configure, Curve curve = null) → T T.IsDragRegion(bool? isDragRegion = true) → T T.IsEnabled(bool enabled = true) → T +T.IsHitTestVisible(bool isHitTestVisible = true) → T T.IsTabStop(bool isTabStop = true) → T T.IsVisible(bool isVisible) → T T.ItemContainerTransitions(Transition[] transitions) → T @@ -2979,6 +2980,7 @@ VisualModifiers Visual { get; init; } XYFocusKeyboardNavigationMode? XYFocusKeyboardNavigation { get; init; } bool? IsDragRegion { get; init; } bool? IsEnabled { get; init; } +bool? IsHitTestVisible { get; init; } bool? IsTabStop { get; init; } bool? IsVisible { get; init; } double? FontSize { get; init; } diff --git a/skills/reactor.api.txt b/skills/reactor.api.txt index 8bc228124..216b25be6 100644 --- a/skills/reactor.api.txt +++ b/skills/reactor.api.txt @@ -608,6 +608,7 @@ T.Immediate() → T T.InteractionStates(Func configure, Curve curve = null) → T T.IsDragRegion(bool? isDragRegion = true) → T T.IsEnabled(bool enabled = true) → T +T.IsHitTestVisible(bool isHitTestVisible = true) → T T.IsTabStop(bool isTabStop = true) → T T.IsVisible(bool isVisible) → T T.ItemContainerTransitions(Transition[] transitions) → T @@ -2979,6 +2980,7 @@ VisualModifiers Visual { get; init; } XYFocusKeyboardNavigationMode? XYFocusKeyboardNavigation { get; init; } bool? IsDragRegion { get; init; } bool? IsEnabled { get; init; } +bool? IsHitTestVisible { get; init; } bool? IsTabStop { get; init; } bool? IsVisible { get; init; } double? FontSize { get; init; } diff --git a/src/Reactor/Core/Element.cs b/src/Reactor/Core/Element.cs index d9ba18408..e00f6fde4 100644 --- a/src/Reactor/Core/Element.cs +++ b/src/Reactor/Core/Element.cs @@ -1191,6 +1191,7 @@ internal static bool ModifiersEqual(ElementModifiers? a, ElementModifiers? b) && a.HeadingLevel == b.HeadingLevel && a.IsDragRegion == b.IsDragRegion && a.IsTabStop == b.IsTabStop + && a.IsHitTestVisible == b.IsHitTestVisible && a.TabIndex == b.TabIndex && a.AccessKey == b.AccessKey && ReferenceEquals(a.XYFocusUpRef, b.XYFocusUpRef) @@ -1997,6 +1998,7 @@ public ElementTheme? RequestedTheme // ── Accessibility — Tier 1 (inline, commonly needed for WCAG AA) ─ public Microsoft.UI.Xaml.Automation.Peers.AutomationHeadingLevel? HeadingLevel { get; init; } public bool? IsTabStop { get; init; } + public bool? IsHitTestVisible { get; init; } public int? TabIndex { get; init; } public string? AccessKey { get; init; } public Microsoft.UI.Xaml.Input.XYFocusKeyboardNavigationMode? XYFocusKeyboardNavigation { get; init; } @@ -2084,6 +2086,7 @@ public ElementModifiers Merge(ElementModifiers other) HeadingLevel = other.HeadingLevel ?? HeadingLevel, IsDragRegion = other.IsDragRegion ?? IsDragRegion, IsTabStop = other.IsTabStop ?? IsTabStop, + IsHitTestVisible = other.IsHitTestVisible ?? IsHitTestVisible, TabIndex = other.TabIndex ?? TabIndex, AccessKey = other.AccessKey ?? AccessKey, XYFocusKeyboardNavigation = other.XYFocusKeyboardNavigation ?? XYFocusKeyboardNavigation, diff --git a/src/Reactor/Core/Reconciler.cs b/src/Reactor/Core/Reconciler.cs index 6f5a91ac8..4dd6aa459 100644 --- a/src/Reactor/Core/Reconciler.cs +++ b/src/Reactor/Core/Reconciler.cs @@ -3832,6 +3832,9 @@ internal void ApplyModifiers(FrameworkElement fe, ElementModifiers? oldM, Elemen if (m.IsTabStop.HasValue && m.IsTabStop != oldM?.IsTabStop) fe.IsTabStop = m.IsTabStop.Value; + if (m.IsHitTestVisible.HasValue && m.IsHitTestVisible != oldM?.IsHitTestVisible) + fe.IsHitTestVisible = m.IsHitTestVisible.Value; + if (m.TabIndex.HasValue && m.TabIndex != oldM?.TabIndex && fe is WinUI.Control tabIdxCtrl) tabIdxCtrl.TabIndex = m.TabIndex.Value; diff --git a/src/Reactor/Elements/ElementExtensions.cs b/src/Reactor/Elements/ElementExtensions.cs index a4017621c..8197820b7 100644 --- a/src/Reactor/Elements/ElementExtensions.cs +++ b/src/Reactor/Elements/ElementExtensions.cs @@ -2517,6 +2517,16 @@ public static T HeadingLevel(this T el, Microsoft.UI.Xaml.Automation.Peers.Au public static T IsTabStop(this T el, bool isTabStop = true) where T : Element => Modify(el, new ElementModifiers { IsTabStop = isTabStop }); + /// + /// Sets UIElement.IsHitTestVisible — whether the element (and its subtree) can be + /// the target of pointer input. Set false for decorative or overlay layers + /// that should let pointer events pass through to whatever is underneath. + /// Works on any element type (Panel, Control, etc.) in WinUI 3. + /// + /// Border(content).IsHitTestVisible(false) + public static T IsHitTestVisible(this T el, bool isHitTestVisible = true) where T : Element => + Modify(el, new ElementModifiers { IsHitTestVisible = isHitTestVisible }); + /// /// Marks how this element participates in a window title bar's drag region /// (Microsoft.UI.Xaml.Controls.TitleBar.IsDragRegion, WinApp SDK ≥ 2.1.3): diff --git a/tests/Reactor.Tests/ElementExtensionsCoverageTests.cs b/tests/Reactor.Tests/ElementExtensionsCoverageTests.cs index c1595f967..92a268098 100644 --- a/tests/Reactor.Tests/ElementExtensionsCoverageTests.cs +++ b/tests/Reactor.Tests/ElementExtensionsCoverageTests.cs @@ -202,6 +202,15 @@ public void IsEnabled_Sets_Modifier() Assert.True(enabled.Modifiers!.IsEnabled); } + [Fact] + public void IsHitTestVisible_Sets_Modifier() + { + var el = Button("Y").IsHitTestVisible(false); + Assert.False(el.Modifiers!.IsHitTestVisible); + var hitTestable = Button("Y").IsHitTestVisible(); + Assert.True(hitTestable.Modifiers!.IsHitTestVisible); + } + [Fact] [Obsolete("Tests the deprecated Disabled shim")] public void Disabled_Shim_Inverts_To_IsEnabled()