fix(visualizer): lift zoom slider out of fixed backdrop's stacking context so it receives pointer events again (P10 W1)

This commit is contained in:
daniel-c-harvey
2026-06-15 21:54:22 -04:00
parent 83c0425133
commit 652c90979d
4 changed files with 37 additions and 21 deletions
@@ -9,20 +9,25 @@
<div class="mix-waveform-bg">
<canvas @ref="_canvas" class="mix-waveform-canvas"></canvas>
@* Viewing control only — never a seek surface. Hidden until a datum is present. *@
@if (_hasDatum)
{
<div class="mix-waveform-zoom">
<MudSlider T="double"
Value="@ZoomFraction"
ValueChanged="@OnZoomFractionChanged"
Min="0"
Max="1"
Step="0.001"
Size="Size.Small"
Color="Color.Primary"
aria-label="Waveform zoom" />
</div>
}
</div>
@* Viewing control only — never a seek surface. Hidden until a datum is present.
Deliberately a SIBLING of .mix-waveform-bg, not a child: the backdrop is position:fixed and so
forms its own stacking context, which would trap any descendant below the page's z-index:1
foreground (.mix-detail-foreground) and let that foreground swallow the slider's pointer events.
As a top-level sibling with its own z-index, the slider stacks above the foreground and stays
draggable. *@
@if (_hasDatum)
{
<div class="mix-waveform-zoom">
<MudSlider T="double"
Value="@ZoomFraction"
ValueChanged="@OnZoomFractionChanged"
Min="0"
Max="1"
Step="0.001"
Size="Size.Small"
Color="Color.Primary"
aria-label="Waveform zoom" />
</div>
}
@@ -180,6 +180,7 @@ public partial class MixWaveformVisualizer : ComponentBase, IAsyncDisposable
private async Task OnZoomFractionChanged(double fraction)
{
ZoomState.VisibleSeconds = MixZoomMapping.FractionToSeconds(fraction);
DebugLog($"zoom slider changed — raw fraction={fraction:F3} → visibleSeconds={ZoomState.VisibleSeconds:F3}s; pushing setZoom (handle={(_handle is null ? "null" : "ready")}).");
await PushZoomAsync();
StateHasChanged();
}
@@ -21,13 +21,18 @@
}
/* Zoom slider — a small viewing control pinned to the top-right, clear of the player bar at
the bottom and the nav bar at the top. Pointer events are re-enabled here only (the backdrop
stays inert), and it is never a seek surface. top: 5rem sits just below the fixed nav bar
(~4.5rem tall) so neither the expanded player bar nor the nav occludes it. */
the bottom and the nav bar at the top. It is never a seek surface. top: 5rem sits just below the
fixed nav bar (~4.5rem tall) so neither the expanded player bar nor the nav occludes it.
position: fixed (not absolute) because the slider is now a top-level sibling of the backdrop, not
a child of it — see the comment in the .razor. z-index: 10 lifts it above the page foreground
(.mix-detail-foreground, z-index: 1) so the foreground can't intercept its pointer events; that
occlusion was the resolution-slider regression. */
.mix-waveform-zoom {
position: absolute;
position: fixed;
right: 1.5rem;
top: 5rem;
z-index: 10;
width: 180px;
max-width: 40vw;
pointer-events: auto;