@implements IAsyncDisposable @inject IJSRuntime JS
@if (_isOpen) { }
@code { [Parameter] public string AriaLabel { get; set; } = "Menu"; [Parameter] public RenderFragment ChildContent { get; set; } = default!; private bool _isOpen; private ElementReference _menuRef; private DotNetObjectReference? _dotNetRef; private IJSObjectReference? _jsRef; private readonly KebabMenuContext _context; public KebabMenu() { _context = new KebabMenuContext(Close); } /// /// Toggles the open state of the menu. /// private void Toggle() { _isOpen = !_isOpen; } /// /// Closes the menu if it is open. /// [JSInvokable] public void Close() { if (!_isOpen) { return; } _isOpen = false; _ = InvokeAsync(StateHasChanged); } /// /// Called after the component has been rendered. Registers the JavaScript event handler on first render. /// /// True if this is the first render; otherwise, false. protected override async Task OnAfterRenderAsync(bool firstRender) { if (!firstRender) { return; } _dotNetRef = DotNetObjectReference.Create(this); _jsRef = await JS.InvokeAsync("kebabMenu.register", _menuRef, _dotNetRef); } /// /// Disposes the JavaScript object reference and event handler. /// public async ValueTask DisposeAsync() { if (_jsRef is not null) { await _jsRef.InvokeVoidAsync("dispose"); await _jsRef.DisposeAsync(); } _dotNetRef?.Dispose(); } /// /// Initializes a new instance of the KebabMenuContext class. /// /// The action to close the menu. public sealed class KebabMenuContext { public KebabMenuContext(Action close) { Close = close; } public Action Close { get; } } }