diff --git a/src/Web/Avalonia.Web.Sample/index.html b/src/Web/Avalonia.Web.Sample/index.html
index a4e017a9aa..3866e2bfa7 100644
--- a/src/Web/Avalonia.Web.Sample/index.html
+++ b/src/Web/Avalonia.Web.Sample/index.html
@@ -13,7 +13,11 @@
-
+
diff --git a/src/Web/Avalonia.Web/AvaloniaView.cs b/src/Web/Avalonia.Web/AvaloniaView.cs
index 73da939110..faba09f66e 100644
--- a/src/Web/Avalonia.Web/AvaloniaView.cs
+++ b/src/Web/Avalonia.Web/AvaloniaView.cs
@@ -1,4 +1,5 @@
using System;
+using System.Runtime.CompilerServices;
using System.Runtime.InteropServices.JavaScript;
using Avalonia.Controls;
using Avalonia.Controls.Embedding;
@@ -8,6 +9,7 @@ using Avalonia.Input.Raw;
using Avalonia.Input.TextInput;
using Avalonia.Platform.Storage;
using Avalonia.Rendering.Composition;
+using Avalonia.Threading;
using Avalonia.Web.Interop;
using SkiaSharp;
@@ -23,6 +25,7 @@ namespace Avalonia.Web
private readonly JSObject _canvas;
private readonly JSObject _nativeControlsContainer;
private readonly JSObject _inputElement;
+ private readonly JSObject? _splash;
private GLInfo? _jsGlInfo = null;
private double _dpi = 1;
@@ -59,11 +62,23 @@ namespace Avalonia.Web
_inputElement = hostContent.GetPropertyAsJSObject("inputElement")
?? throw new InvalidOperationException("InputElement cannot be null");
+ _splash = DomHelper.GetElementById("avalonia-splash");
+
_canvas.SetProperty("id", $"avaloniaCanvas{_canvasCount++}");
_topLevelImpl = new BrowserTopLevelImpl(this);
- _topLevel = new EmbeddableControlRoot(_topLevelImpl);
+ _topLevel = new WebEmbeddableControlRoot(_topLevelImpl, () =>
+ {
+ Dispatcher.UIThread.Post(() =>
+ {
+ if (_splash != null)
+ {
+ InputHelper.HideElement(_splash);
+ }
+ });
+ });
+
_topLevelImpl.SetCssCursor = (cursor) =>
{
InputHelper.SetCursor(_containerElement, cursor); // macOS
diff --git a/src/Web/Avalonia.Web/Interop/DomHelper.cs b/src/Web/Avalonia.Web/Interop/DomHelper.cs
index 1167d21a6b..f1d98a9d24 100644
--- a/src/Web/Avalonia.Web/Interop/DomHelper.cs
+++ b/src/Web/Avalonia.Web/Interop/DomHelper.cs
@@ -6,7 +6,7 @@ namespace Avalonia.Web.Interop;
internal static partial class DomHelper
{
[JSImport("globalThis.document.getElementById")]
- internal static partial JSObject GetElementById(string id);
+ internal static partial JSObject? GetElementById(string id);
[JSImport("AvaloniaDOM.createAvaloniaHost", "avalonia.ts")]
public static partial JSObject CreateAvaloniaHost(JSObject element);
diff --git a/src/Web/Avalonia.Web/WebEmbeddableControlRoot.cs b/src/Web/Avalonia.Web/WebEmbeddableControlRoot.cs
new file mode 100644
index 0000000000..19f36403ad
--- /dev/null
+++ b/src/Web/Avalonia.Web/WebEmbeddableControlRoot.cs
@@ -0,0 +1,68 @@
+using System;
+using Avalonia.Controls.Embedding;
+using Avalonia.Media;
+using Avalonia.Platform;
+using Avalonia.Rendering.SceneGraph;
+
+namespace Avalonia.Web
+{
+ internal class WebEmbeddableControlRoot : EmbeddableControlRoot
+ {
+ class SplashScreenCloseCustomDrawingOperation : ICustomDrawOperation
+ {
+ private bool _hasRendered;
+ private Action _onFirstRender;
+
+ public SplashScreenCloseCustomDrawingOperation(Action onFirstRender)
+ {
+ _onFirstRender = onFirstRender;
+ }
+
+ public Rect Bounds => Rect.Empty;
+
+ public bool HasRendered => _hasRendered;
+
+ public void Dispose()
+ {
+
+ }
+
+ public bool Equals(ICustomDrawOperation? other)
+ {
+ return false;
+ }
+
+ public bool HitTest(Point p)
+ {
+ return false;
+ }
+
+ public void Render(IDrawingContextImpl context)
+ {
+ _hasRendered = true;
+ _onFirstRender();
+ }
+ }
+
+ public WebEmbeddableControlRoot(ITopLevelImpl impl, Action onFirstRender) : base(impl)
+ {
+ _splashCloseOp = new SplashScreenCloseCustomDrawingOperation(() =>
+ {
+ _splashCloseOp = null;
+ onFirstRender();
+ });
+ }
+
+ private SplashScreenCloseCustomDrawingOperation? _splashCloseOp;
+
+ public override void Render(DrawingContext context)
+ {
+ base.Render(context);
+
+ if (_splashCloseOp != null)
+ {
+ context.Custom(_splashCloseOp);
+ }
+ }
+ }
+}
diff --git a/src/Web/Avalonia.Web/webapp/modules/avalonia/dom.ts b/src/Web/Avalonia.Web/webapp/modules/avalonia/dom.ts
index ad6d451343..48b6f9c45f 100644
--- a/src/Web/Avalonia.Web/webapp/modules/avalonia/dom.ts
+++ b/src/Web/Avalonia.Web/webapp/modules/avalonia/dom.ts
@@ -12,7 +12,6 @@ export class AvaloniaDOM {
canvas.style.width = "100%";
canvas.style.height = "100%";
canvas.style.position = "absolute";
- host.appendChild(canvas);
// Native controls host
const nativeHost = document.createElement("div");
@@ -22,7 +21,6 @@ export class AvaloniaDOM {
nativeHost.style.width = "100%";
nativeHost.style.height = "100%";
nativeHost.style.position = "absolute";
- host.appendChild(nativeHost);
// IME
const inputElement = document.createElement("input");
@@ -43,7 +41,10 @@ export class AvaloniaDOM {
inputElement.onpaste = function () { return false; };
inputElement.oncopy = function () { return false; };
inputElement.oncut = function () { return false; };
- host.appendChild(inputElement);
+
+ host.prepend(inputElement);
+ host.prepend(nativeHost);
+ host.prepend(canvas);
return {
host,