review(track0): async ContextMenu OnClick + keyboard-⋯ anchoring + focus-return; discovery-driven DriverTypeNames guard; CSV round-trip comment

Wave-0 reviewer findings (no Critical/High):
- T0-1 M: ContextMenuItem.OnClick Action→Func<Task> (kills async-void at menu call sites Wave A/B/C need); keyboard-activated ⋯ now anchors below the button instead of viewport (0,0); focus returns to trigger on close; backdrop closes on native right-click too.
- T0-3 M: guard test now discovers *DriverFactoryExtensions.Register by convention from the deployed driver assemblies instead of a hand-copied list, so a future driver lacking a constant is actually caught.
- T0-2 L: corrected the round-trip 'sole non-round-trippable shape' comment (any table whose final row is a lone empty field).

Claude-Session: https://claude.ai/code/session_01LVneM3eh1UtJxEisFXgmox
This commit is contained in:
Joseph Doherty
2026-07-16 02:17:37 -04:00
parent 9a896efecd
commit c3277b52c9
6 changed files with 169 additions and 81 deletions
@@ -11,8 +11,13 @@ public sealed class ContextMenuItem
/// <summary>Text shown for the row.</summary>
public string Label { get; init; } = "";
/// <summary>Invoked when the row is activated (click / Enter).</summary>
public Action? OnClick { get; init; }
/// <summary>
/// Invoked when the row is activated (click / Enter). Async so per-node menu
/// actions (delete, redeploy, rename) can await their service calls without an
/// exception-swallowing <c>async void</c>; the menu awaits this and re-renders.
/// A synchronous handler returns <see cref="Task.CompletedTask"/>.
/// </summary>
public Func<Task>? OnClick { get; init; }
/// <summary>Optional leading icon — an emoji or single glyph.</summary>
public string? Icon { get; init; }