diff --git a/samples/SafeAreaDemo/ViewModels/MainViewModel.cs b/samples/SafeAreaDemo/ViewModels/MainViewModel.cs
index 3d826d8a9c..c52536d157 100644
--- a/samples/SafeAreaDemo/ViewModels/MainViewModel.cs
+++ b/samples/SafeAreaDemo/ViewModels/MainViewModel.cs
@@ -1,4 +1,6 @@
-using Avalonia;
+using System;
+using Avalonia;
+using Avalonia.Animation.Easings;
using Avalonia.Controls;
using Avalonia.Controls.Platform;
using MiniMvvm;
@@ -12,7 +14,26 @@ namespace SafeAreaDemo.ViewModels
private IInsetsManager? _insetsManager;
private bool _hideSystemBars;
private bool _autoSafeAreaPadding;
+ private IInputPane? _inputPane;
+ public InputPaneState InputPaneState
+ {
+ get
+ {
+ return _inputPane?.State ?? InputPaneState.Closed;
+ }
+ }
+
+ public IEasing? InputPaneEasing { get; private set; }
+ public TimeSpan? InputPaneDuration { get; private set; }
+
+ public Thickness InputPaneMarkerMargin => InputPaneState == InputPaneState.Open
+ ? new Thickness(0, 0, 0, Math.Max(0, CanvasSize.Height - InputPaneRect.Top))
+ : default;
+ public Rect InputPaneRect => _inputPane?.OccludedRect ?? default;
+
+ public Rect CanvasSize { get; set; }
+
public Thickness SafeAreaPadding
{
get
@@ -90,12 +111,16 @@ namespace SafeAreaDemo.ViewModels
}
}
- internal void Initialize(Control mainView, IInsetsManager? InsetsManager)
+ internal void Initialize(Control mainView, IInsetsManager? InsetsManager, IInputPane? inputPane)
{
if (_insetsManager != null)
{
_insetsManager.SafeAreaChanged -= InsetsManager_SafeAreaChanged;
}
+ if (_inputPane != null)
+ {
+ _inputPane.StateChanged -= InputPaneOnStateChanged;
+ }
_autoSafeAreaPadding = mainView.GetValue(TopLevel.AutoSafeAreaPaddingProperty);
_insetsManager = InsetsManager;
@@ -107,6 +132,20 @@ namespace SafeAreaDemo.ViewModels
_displayEdgeToEdge = _insetsManager.DisplayEdgeToEdge;
_hideSystemBars = !(_insetsManager.IsSystemBarVisible ?? false);
}
+
+ _inputPane = inputPane;
+ if (_inputPane != null)
+ {
+ _inputPane.StateChanged += InputPaneOnStateChanged;
+ }
+ RaiseKeyboardChanged();
+ }
+
+ private void InputPaneOnStateChanged(object? sender, InputPaneStateEventArgs e)
+ {
+ InputPaneDuration = e.AnimationDuration;
+ InputPaneEasing = e.Easing ?? new LinearEasing();
+ RaiseKeyboardChanged();
}
private void InsetsManager_SafeAreaChanged(object? sender, SafeAreaChangedArgs e)
@@ -118,6 +157,16 @@ namespace SafeAreaDemo.ViewModels
{
this.RaisePropertyChanged(nameof(SafeAreaPadding));
this.RaisePropertyChanged(nameof(ViewPadding));
+ this.RaisePropertyChanged(nameof(InputPaneMarkerMargin));
+ }
+
+ private void RaiseKeyboardChanged()
+ {
+ this.RaisePropertyChanged(nameof(InputPaneState));
+ this.RaisePropertyChanged(nameof(InputPaneRect));
+ this.RaisePropertyChanged(nameof(InputPaneEasing));
+ this.RaisePropertyChanged(nameof(InputPaneDuration));
+ this.RaisePropertyChanged(nameof(InputPaneMarkerMargin));
}
}
}
diff --git a/samples/SafeAreaDemo/Views/MainView.xaml b/samples/SafeAreaDemo/Views/MainView.xaml
index 966b0a02ea..85163e7dad 100644
--- a/samples/SafeAreaDemo/Views/MainView.xaml
+++ b/samples/SafeAreaDemo/Views/MainView.xaml
@@ -11,10 +11,11 @@
Background="#ccc"
TopLevel.AutoSafeAreaPadding="{Binding AutoSafeAreaPadding, Mode=TwoWay}">
-
+ VerticalAlignment="Stretch"
+ Bounds="{Binding CanvasSize, Mode=OneWayToSource}">
+
+
diff --git a/samples/SafeAreaDemo/Views/MainView.xaml.cs b/samples/SafeAreaDemo/Views/MainView.xaml.cs
index bacb721d27..e4cd53c1a4 100644
--- a/samples/SafeAreaDemo/Views/MainView.xaml.cs
+++ b/samples/SafeAreaDemo/Views/MainView.xaml.cs
@@ -18,8 +18,9 @@ namespace SafeAreaDemo.Views
base.OnLoaded(e);
var insetsManager = TopLevel.GetTopLevel(this)?.InsetsManager;
+ var inputPane = TopLevel.GetTopLevel(this)?.InputPane;
var viewModel = new MainViewModel();
- viewModel.Initialize(this, insetsManager);
+ viewModel.Initialize(this, insetsManager, inputPane);
DataContext = viewModel;
}
}
diff --git a/src/Android/Avalonia.Android/Platform/AndroidInsetsManager.cs b/src/Android/Avalonia.Android/Platform/AndroidInsetsManager.cs
index 6d8ae873a2..c38124e6da 100644
--- a/src/Android/Avalonia.Android/Platform/AndroidInsetsManager.cs
+++ b/src/Android/Avalonia.Android/Platform/AndroidInsetsManager.cs
@@ -2,53 +2,68 @@
using System.Collections.Generic;
using Android.OS;
using Android.Views;
+using Android.Views.Animations;
using AndroidX.Core.View;
using Avalonia.Android.Platform.SkiaPlatform;
+using Avalonia.Animation.Easings;
using Avalonia.Controls.Platform;
using Avalonia.Media;
+using AndroidWindow = Android.Views.Window;
namespace Avalonia.Android.Platform
{
- internal class AndroidInsetsManager : Java.Lang.Object, IInsetsManager, IOnApplyWindowInsetsListener, ViewTreeObserver.IOnGlobalLayoutListener
+ internal sealed class AndroidInsetsManager : WindowInsetsAnimationCompat.Callback, IInsetsManager, IOnApplyWindowInsetsListener, ViewTreeObserver.IOnGlobalLayoutListener, IInputPane
{
private readonly AvaloniaMainActivity _activity;
private readonly TopLevelImpl _topLevel;
- private readonly InsetsAnimationCallback _callback;
private bool _displayEdgeToEdge;
- private bool _usesLegacyLayouts;
private bool? _systemUiVisibility;
private SystemBarTheme? _statusBarTheme;
private bool? _isDefaultSystemBarLightTheme;
private Color? _systemBarColor;
+ private InputPaneState _state;
+ private Rect _previousRect;
+ private readonly bool _usesLegacyLayouts;
+ private AndroidWindow Window => _activity.Window ?? throw new InvalidOperationException("Activity.Window must be set.");
+
public event EventHandler SafeAreaChanged;
+ public event EventHandler StateChanged;
+
+ public InputPaneState State
+ {
+ get => _state; set
+ {
+ var oldState = _state;
+ _state = value;
+
+ if (oldState != value && Build.VERSION.SdkInt <= BuildVersionCodes.Q)
+ {
+ var currentRect = OccludedRect;
+ StateChanged?.Invoke(this, new InputPaneStateEventArgs(value, _previousRect, currentRect, TimeSpan.Zero, null));
+ _previousRect = currentRect;
+ }
+ }
+ }
public bool DisplayEdgeToEdge
{
- get => _displayEdgeToEdge;
+ get => _displayEdgeToEdge;
set
{
_displayEdgeToEdge = value;
- var window = _activity.Window;
-
- if (OperatingSystem.IsAndroidVersionAtLeast(28) && window?.Attributes is { } attributes)
+ if (OperatingSystem.IsAndroidVersionAtLeast(28) && Window.Attributes is { } attributes)
{
attributes.LayoutInDisplayCutoutMode = value ? LayoutInDisplayCutoutMode.ShortEdges : LayoutInDisplayCutoutMode.Default;
}
- if (window is not null)
- {
- WindowCompat.SetDecorFitsSystemWindows(_activity.Window, !value);
- }
+ WindowCompat.SetDecorFitsSystemWindows(Window, !value);
- if(value)
+ if (value)
{
- if (window is not null)
- {
- window.AddFlags(WindowManagerFlags.TranslucentStatus);
- window.AddFlags(WindowManagerFlags.TranslucentNavigation);
- }
+ Window.AddFlags(WindowManagerFlags.TranslucentStatus);
+ Window.AddFlags(WindowManagerFlags.TranslucentNavigation);
}
else
{
@@ -57,20 +72,12 @@ namespace Avalonia.Android.Platform
}
}
- public AndroidInsetsManager(AvaloniaMainActivity activity, TopLevelImpl topLevel)
+ internal AndroidInsetsManager(AvaloniaMainActivity activity, TopLevelImpl topLevel) : base(DispatchModeStop)
{
_activity = activity;
_topLevel = topLevel;
- _callback = new InsetsAnimationCallback(WindowInsetsAnimationCompat.Callback.DispatchModeStop);
-
- _callback.InsetsManager = this;
-
- if (_activity.Window is { } window)
- {
- ViewCompat.SetOnApplyWindowInsetsListener(window.DecorView, this);
- ViewCompat.SetWindowInsetsAnimationCallback(window.DecorView, _callback);
- }
+ ViewCompat.SetOnApplyWindowInsetsListener(Window.DecorView, this);
if (Build.VERSION.SdkInt < BuildVersionCodes.R)
{
@@ -79,32 +86,48 @@ namespace Avalonia.Android.Platform
}
DisplayEdgeToEdge = false;
+
+ ViewCompat.SetWindowInsetsAnimationCallback(Window.DecorView, this);
}
public Thickness SafeAreaPadding
{
get
{
- var insets = _activity.Window is { } window ? ViewCompat.GetRootWindowInsets(window.DecorView) : null;
+ var insets = ViewCompat.GetRootWindowInsets(Window.DecorView);
if (insets != null)
{
var renderScaling = _topLevel.RenderScaling;
var inset = insets.GetInsets(
- (_displayEdgeToEdge ?
+ _displayEdgeToEdge ?
WindowInsetsCompat.Type.StatusBars() | WindowInsetsCompat.Type.NavigationBars() |
- WindowInsetsCompat.Type.DisplayCutout() :
- 0) | WindowInsetsCompat.Type.Ime());
- var navBarInset = insets.GetInsets(WindowInsetsCompat.Type.NavigationBars());
- var imeInset = insets.GetInsets(WindowInsetsCompat.Type.Ime());
+ WindowInsetsCompat.Type.DisplayCutout() : 0);
return new Thickness(inset.Left / renderScaling,
inset.Top / renderScaling,
inset.Right / renderScaling,
- (imeInset.Bottom > 0 && ((_usesLegacyLayouts && !_displayEdgeToEdge) || !_usesLegacyLayouts) ?
- imeInset.Bottom - (_displayEdgeToEdge ? 0 : navBarInset.Bottom) :
- inset.Bottom) / renderScaling);
+ inset.Bottom / renderScaling);
+ }
+
+ return default;
+ }
+ }
+
+ public Rect OccludedRect
+ {
+ get
+ {
+ var insets = ViewCompat.GetRootWindowInsets(Window.DecorView);
+
+ if (insets != null)
+ {
+ var navbarInset = insets.GetInsets(WindowInsetsCompat.Type.NavigationBars()).Bottom;
+
+ var height = Math.Max((float)((insets.GetInsets(WindowInsetsCompat.Type.Ime()).Bottom - navbarInset) / _topLevel.RenderScaling), 0);
+
+ return new Rect(0, _topLevel.ClientSize.Height - SafeAreaPadding.Bottom - height, _topLevel.ClientSize.Width, height);
}
return default;
@@ -113,8 +136,16 @@ namespace Avalonia.Android.Platform
public WindowInsetsCompat OnApplyWindowInsets(View v, WindowInsetsCompat insets)
{
- NotifySafeAreaChanged(SafeAreaPadding);
insets = ViewCompat.OnApplyWindowInsets(v, insets);
+ NotifySafeAreaChanged(SafeAreaPadding);
+
+ if (_previousRect == default)
+ {
+ _previousRect = OccludedRect;
+ }
+
+ State = insets.IsVisible(WindowInsetsCompat.Type.Ime()) ? InputPaneState.Open : InputPaneState.Closed;
+
return insets;
}
@@ -126,6 +157,12 @@ namespace Avalonia.Android.Platform
public void OnGlobalLayout()
{
NotifySafeAreaChanged(SafeAreaPadding);
+
+ if (_usesLegacyLayouts)
+ {
+ var insets = ViewCompat.GetRootWindowInsets(Window.DecorView);
+ State = insets?.IsVisible(WindowInsetsCompat.Type.Ime()) == true ? InputPaneState.Open : InputPaneState.Closed;
+ }
}
public SystemBarTheme? SystemBarTheme
@@ -134,7 +171,7 @@ namespace Avalonia.Android.Platform
{
try
{
- var compat = new WindowInsetsControllerCompat(_activity.Window, _topLevel.View);
+ var compat = new WindowInsetsControllerCompat(Window, _topLevel.View);
return compat.AppearanceLightStatusBars ? Controls.Platform.SystemBarTheme.Light : Controls.Platform.SystemBarTheme.Dark;
}
@@ -152,7 +189,7 @@ namespace Avalonia.Android.Platform
return;
}
- var compat = new WindowInsetsControllerCompat(_activity.Window, _topLevel.View);
+ var compat = new WindowInsetsControllerCompat(Window, _topLevel.View);
if (_isDefaultSystemBarLightTheme == null)
{
@@ -161,7 +198,7 @@ namespace Avalonia.Android.Platform
if (value == null)
{
- value = (bool)_isDefaultSystemBarLightTheme ? Controls.Platform.SystemBarTheme.Light : Controls.Platform.SystemBarTheme.Dark;
+ value = _isDefaultSystemBarLightTheme.Value ? Controls.Platform.SystemBarTheme.Light : Controls.Platform.SystemBarTheme.Dark;
}
compat.AppearanceLightStatusBars = value == Controls.Platform.SystemBarTheme.Light;
@@ -173,7 +210,7 @@ namespace Avalonia.Android.Platform
{
get
{
- if(_activity.Window == null)
+ if (_activity.Window == null)
{
return true;
}
@@ -190,7 +227,7 @@ namespace Avalonia.Android.Platform
return;
}
- var compat = WindowCompat.GetInsetsController(_activity.Window, _topLevel.View);
+ var compat = WindowCompat.GetInsetsController(Window, _topLevel.View);
if (value == null || value.Value)
{
@@ -210,7 +247,7 @@ namespace Avalonia.Android.Platform
public Color? SystemBarColor
{
- get => _systemBarColor;
+ get => _systemBarColor;
set
{
_systemBarColor = value;
@@ -240,40 +277,48 @@ namespace Avalonia.Android.Platform
SystemBarColor = _systemBarColor;
}
- private class InsetsAnimationCallback : WindowInsetsAnimationCompat.Callback
+ public override WindowInsetsAnimationCompat.BoundsCompat OnStart(WindowInsetsAnimationCompat animation, WindowInsetsAnimationCompat.BoundsCompat bounds)
{
- public InsetsAnimationCallback(int dispatchMode) : base(dispatchMode)
+ if ((animation.TypeMask & WindowInsetsCompat.Type.Ime()) != 0)
{
- }
-
- public AndroidInsetsManager InsetsManager { get; set; }
+ var insets = ViewCompat.GetRootWindowInsets(Window.DecorView);
- public override WindowInsetsCompat OnProgress(WindowInsetsCompat insets, IList runningAnimations)
- {
- foreach (var anim in runningAnimations)
+ if (insets != null)
{
- if ((anim.TypeMask & WindowInsetsCompat.Type.Ime()) != 0)
- {
- var renderScaling = InsetsManager._topLevel.RenderScaling;
-
- var inset = insets.GetInsets((InsetsManager.DisplayEdgeToEdge ? WindowInsetsCompat.Type.StatusBars() | WindowInsetsCompat.Type.NavigationBars() | WindowInsetsCompat.Type.DisplayCutout() : 0) | WindowInsetsCompat.Type.Ime());
- var navBarInset = insets.GetInsets(WindowInsetsCompat.Type.NavigationBars());
- var imeInset = insets.GetInsets(WindowInsetsCompat.Type.Ime());
+ var navbarInset = insets.GetInsets(WindowInsetsCompat.Type.NavigationBars()).Bottom;
+ var height = Math.Max(0, (float)((bounds.LowerBound.Bottom - navbarInset) / _topLevel.RenderScaling));
+ var upperRect = new Rect(0, _topLevel.ClientSize.Height - SafeAreaPadding.Bottom - height, _topLevel.ClientSize.Width, height);
+ height = Math.Max(0, (float)((bounds.UpperBound.Bottom - navbarInset) / _topLevel.RenderScaling));
+ var lowerRect = new Rect(0, _topLevel.ClientSize.Height - SafeAreaPadding.Bottom - height, _topLevel.ClientSize.Width, height);
+ var duration = TimeSpan.FromMilliseconds(animation.DurationMillis);
- var bottomPadding = (imeInset.Bottom > 0 && !InsetsManager.DisplayEdgeToEdge ? imeInset.Bottom - navBarInset.Bottom : inset.Bottom);
- bottomPadding = (int)(bottomPadding * anim.InterpolatedFraction);
-
- var padding = new Thickness(inset.Left / renderScaling,
- inset.Top / renderScaling,
- inset.Right / renderScaling,
- bottomPadding / renderScaling);
- InsetsManager?.NotifySafeAreaChanged(padding);
- break;
- }
+ bool isOpening = State == InputPaneState.Open;
+ StateChanged?.Invoke(this, new InputPaneStateEventArgs(State, isOpening ? upperRect : lowerRect, isOpening ? lowerRect : upperRect, duration, new AnimationEasing(animation.Interpolator)));
}
- return insets;
}
+
+ return base.OnStart(animation, bounds);
+ }
+
+ public override WindowInsetsCompat OnProgress(WindowInsetsCompat insets, IList runningAnimations)
+ {
+ return insets;
+ }
+ }
+
+ internal sealed class AnimationEasing : Easing
+ {
+ private readonly IInterpolator _interpolator;
+
+ public AnimationEasing(IInterpolator interpolator)
+ {
+ _interpolator = interpolator;
+ }
+
+ public override double Ease(double progress)
+ {
+ return _interpolator.GetInterpolation((float)progress);
}
}
}
diff --git a/src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs b/src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs
index d1ef928367..5d5f01db94 100644
--- a/src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs
+++ b/src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs
@@ -395,7 +395,7 @@ namespace Avalonia.Android.Platform.SkiaPlatform
return _nativeControlHost;
}
- if (featureType == typeof(IInsetsManager))
+ if (featureType == typeof(IInsetsManager) || featureType == typeof(IInputPane))
{
return _insetsManager;
}
diff --git a/src/Avalonia.Controls/Platform/IInputPane.cs b/src/Avalonia.Controls/Platform/IInputPane.cs
new file mode 100644
index 0000000000..c36788570c
--- /dev/null
+++ b/src/Avalonia.Controls/Platform/IInputPane.cs
@@ -0,0 +1,89 @@
+using System;
+using Avalonia.Animation.Easings;
+using Avalonia.Metadata;
+
+namespace Avalonia.Controls.Platform
+{
+ ///
+ /// Listener for the platform's input pane(eg, software keyboard). Provides access to the input pane height and state.
+ ///
+ [NotClientImplementable]
+ public interface IInputPane
+ {
+ ///
+ /// The current input pane state
+ ///
+ InputPaneState State { get; }
+
+ ///
+ /// The current input pane bounds.
+ ///
+ Rect OccludedRect { get; }
+
+ ///
+ /// Occurs when the input pane's state has changed.
+ ///
+ event EventHandler? StateChanged;
+ }
+
+ ///
+ /// The input pane opened state.
+ ///
+ public enum InputPaneState
+ {
+ ///
+ /// The input pane is either closed, or doesn't form part of the platform insets, i.e. it's floating or is an overlay.
+ ///
+ Closed,
+
+ ///
+ /// The input pane is open.
+ ///
+ Open
+ }
+
+ ///
+ /// Provides state change information about the input pane.
+ ///
+ public sealed class InputPaneStateEventArgs : EventArgs
+ {
+ ///
+ /// The new state of the input pane
+ ///
+ public InputPaneState NewState { get; }
+
+ ///
+ /// The initial bounds of the input pane.
+ ///
+ public Rect? StartRect { get; }
+
+ ///
+ /// The final bounds of the input pane.
+ ///
+ public Rect EndRect { get; }
+
+ ///
+ /// The duration of the input pane's state change animation.
+ ///
+ public TimeSpan AnimationDuration { get; }
+
+ ///
+ /// The easing of the input pane's state changed animation.
+ ///
+ public IEasing? Easing { get; }
+
+ public InputPaneStateEventArgs(InputPaneState newState, Rect? startRect, Rect endRect, TimeSpan animationDuration, IEasing? easing)
+ {
+ NewState = newState;
+ StartRect = startRect;
+ EndRect = endRect;
+ AnimationDuration = animationDuration;
+ Easing = easing;
+ }
+
+ public InputPaneStateEventArgs(InputPaneState newState, Rect? startRect, Rect endRect)
+ : this(newState, startRect, endRect, default, null)
+ {
+ }
+ }
+}
diff --git a/src/Avalonia.Controls/TopLevel.cs b/src/Avalonia.Controls/TopLevel.cs
index 6898879b32..5026896d41 100644
--- a/src/Avalonia.Controls/TopLevel.cs
+++ b/src/Avalonia.Controls/TopLevel.cs
@@ -547,6 +547,7 @@ namespace Avalonia.Controls
?? new NoopStorageProvider();
public IInsetsManager? InsetsManager => PlatformImpl?.TryGetFeature();
+ public IInputPane? InputPane => PlatformImpl?.TryGetFeature();
///
/// Gets the platform's clipboard implementation
diff --git a/src/Browser/Avalonia.Browser/AvaloniaView.cs b/src/Browser/Avalonia.Browser/AvaloniaView.cs
index 86323afbbd..c1084ee62c 100644
--- a/src/Browser/Avalonia.Browser/AvaloniaView.cs
+++ b/src/Browser/Avalonia.Browser/AvaloniaView.cs
@@ -70,7 +70,7 @@ namespace Avalonia.Browser
_splash = DomHelper.GetElementById("avalonia-splash");
- _topLevelImpl = new BrowserTopLevelImpl(this);
+ _topLevelImpl = new BrowserTopLevelImpl(this, _containerElement);
_topLevel = new WebEmbeddableControlRoot(_topLevelImpl, () =>
{
diff --git a/src/Browser/Avalonia.Browser/BrowserInputPane.cs b/src/Browser/Avalonia.Browser/BrowserInputPane.cs
new file mode 100644
index 0000000000..0b96599fcc
--- /dev/null
+++ b/src/Browser/Avalonia.Browser/BrowserInputPane.cs
@@ -0,0 +1,37 @@
+using System;
+using System.Runtime.InteropServices.JavaScript;
+using Avalonia.Browser.Interop;
+using Avalonia.Controls.Platform;
+
+namespace Avalonia.Browser;
+
+internal class BrowserInputPane : IInputPane
+{
+ public BrowserInputPane(JSObject container)
+ {
+ InputHelper.SubscribeKeyboardGeometryChange(container, OnGeometryChange);
+ }
+
+ public InputPaneState State { get; private set; }
+ public Rect OccludedRect { get; private set; }
+ public event EventHandler? StateChanged;
+
+ private bool OnGeometryChange(JSObject args)
+ {
+ var oldState = (OccludedRect, State);
+
+ OccludedRect = new Rect(
+ args.GetPropertyAsDouble("x"),
+ args.GetPropertyAsDouble("y"),
+ args.GetPropertyAsDouble("width"),
+ args.GetPropertyAsDouble("height"));
+ State = OccludedRect.Width != 0 ? InputPaneState.Open : InputPaneState.Closed;
+
+ if (oldState != (OccludedRect, State))
+ {
+ StateChanged?.Invoke(this, new InputPaneStateEventArgs(State, null, OccludedRect));
+ }
+
+ return true;
+ }
+}
diff --git a/src/Browser/Avalonia.Browser/BrowserTopLevelImpl.cs b/src/Browser/Avalonia.Browser/BrowserTopLevelImpl.cs
index 0809f3a42c..cda0c02a2a 100644
--- a/src/Browser/Avalonia.Browser/BrowserTopLevelImpl.cs
+++ b/src/Browser/Avalonia.Browser/BrowserTopLevelImpl.cs
@@ -2,6 +2,7 @@ using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
+using System.Runtime.InteropServices.JavaScript;
using System.Runtime.Versioning;
using Avalonia.Browser.Skia;
using Avalonia.Browser.Storage;
@@ -33,8 +34,9 @@ namespace Avalonia.Browser
private readonly ISystemNavigationManagerImpl _systemNavigationManager;
private readonly ClipboardImpl _clipboard;
private readonly IInsetsManager? _insetsManager;
+ private readonly IInputPane _inputPane;
- public BrowserTopLevelImpl(AvaloniaView avaloniaView)
+ public BrowserTopLevelImpl(AvaloniaView avaloniaView, JSObject container)
{
Surfaces = Enumerable.Empty