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 @@ -
+
+
+ Loading +
+
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,