fix(theater): replace max-height collapse with grid-rows + visibility; fix keyboard-focus leak when collapsed
This commit is contained in:
@@ -20,7 +20,9 @@ else
|
||||
{
|
||||
var nowShowing = VisualizerControlState.TheaterMode;
|
||||
<div class="dd-theater-collapsible @(nowShowing ? null : "dd-theater-collapsed")">
|
||||
<div class="dd-theater-collapsible-inner">
|
||||
<NowShowingPanel Release="CurrentTrack.Release" />
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
|
||||
@@ -75,6 +75,7 @@ else
|
||||
a collapsing wrapper so it does not pop — IsContentHidden collapses it to zero height when
|
||||
Theater is on AND this Cut is the playing release. OFF eases it back to its normal layout. *@
|
||||
<div class="dd-theater-collapsible @(IsContentHidden ? "dd-theater-collapsed" : null)">
|
||||
<div class="dd-theater-collapsible-inner">
|
||||
@* Header split: meta + Play/Share on the LEFT, bordered cover on the RIGHT (spec §3.1). *@
|
||||
<div class="cut-detail-header">
|
||||
<div class="cut-detail-meta">
|
||||
@@ -134,10 +135,12 @@ else
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Header>
|
||||
<BodyContent>
|
||||
@* Theater Mode (Wave 2 §2): eased collapse, mirroring the Header region. *@
|
||||
<div class="dd-theater-collapsible @(IsContentHidden ? "dd-theater-collapsed" : null)">
|
||||
<div class="dd-theater-collapsible-inner">
|
||||
@* Blurb sits between the header and the track-list divider. *@
|
||||
<ReleaseDescription Description="@release.Description" />
|
||||
<MudDivider Class="cut-detail-divider" />
|
||||
@@ -169,6 +172,7 @@ else
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</BodyContent>
|
||||
</ReleaseDetailScaffold>
|
||||
</div>
|
||||
|
||||
@@ -75,6 +75,7 @@ else
|
||||
a collapsing wrapper so it does not pop — collapsed to zero height when Theater is on AND
|
||||
this Mix is the playing release. OFF eases the full-bleed visualizer back behind the hero. *@
|
||||
<div class="dd-theater-collapsible @(IsContentHidden ? "dd-theater-collapsed" : null)">
|
||||
<div class="dd-theater-collapsible-inner">
|
||||
@* Cover-as-background hero with all metadata overlaid, square `mix-hero` sizing. The
|
||||
cover art IS the background, so no separate cover thumbnail (CoverThumbKey defaults
|
||||
to null). Share and play ride in as slots, matching Sessions. *@
|
||||
@@ -99,12 +100,15 @@ else
|
||||
</PlayContent>
|
||||
</ReleaseHeroOverlay>
|
||||
</div>
|
||||
</div>
|
||||
</Hero>
|
||||
<BodyContent>
|
||||
@* Theater Mode (Wave 2 §2): eased collapse, mirroring the Hero region. *@
|
||||
<div class="dd-theater-collapsible @(IsContentHidden ? "dd-theater-collapsed" : null)">
|
||||
<div class="dd-theater-collapsible-inner">
|
||||
@* Blurb sits below the hero, inside the scaffold's foreground stacking context. *@
|
||||
<ReleaseDescription Description="@release.Description" />
|
||||
</div>
|
||||
</div>
|
||||
</BodyContent>
|
||||
</ReleaseDetailScaffold>
|
||||
|
||||
@@ -72,6 +72,7 @@ else
|
||||
collapsing wrapper so they do not pop — collapsed to zero height when Theater is on AND this
|
||||
Session is the playing release. The top row above stays. OFF eases this region back in. *@
|
||||
<div class="dd-theater-collapsible @(IsContentHidden ? "dd-theater-collapsed" : null)">
|
||||
<div class="dd-theater-collapsible-inner">
|
||||
@* The overlay shows the cover thumbnail only when it differs from the resolved hero image —
|
||||
when there is no dedicated hero, heroImage already falls back to release.ImagePath, so the
|
||||
thumb would duplicate the background. That logic lives in ReleaseHeroOverlay. *@
|
||||
@@ -98,6 +99,7 @@ else
|
||||
|
||||
<ReleaseDescription Description="@release.Description" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</MudContainer>
|
||||
}
|
||||
|
||||
@@ -370,21 +370,44 @@ h2, h3, h4, h5, h6,
|
||||
}
|
||||
|
||||
/* Eased content collapse for Theater Mode (Phase 20 Wave 2 §2). The detail content stays mounted and
|
||||
collapses to zero height (and fades) when .dd-theater-collapsed is applied, so toggling Theater eases
|
||||
both directions instead of popping — when collapsed the content is fully out of the way and the
|
||||
visualizer is unobstructed. overflow:hidden clips the content during the transition; the large open
|
||||
max-height accommodates any realistic content height (it is a ceiling, not a fixed size). The same
|
||||
pattern drives the player-bar "now showing" band so the bar grows/shrinks smoothly too. */
|
||||
collapses smoothly when .dd-theater-collapsed is applied, so toggling Theater eases both directions
|
||||
instead of popping — when collapsed the content is fully out of the way and the visualizer is
|
||||
unobstructed. The same pattern drives the player-bar "now showing" band so the bar grows/shrinks
|
||||
smoothly too.
|
||||
|
||||
Technique: grid-template-rows 1fr → 0fr interpolates the REAL content height (no 400vh ceiling
|
||||
artifact / delayed-start that the old max-height approach had). The direct child receives
|
||||
overflow:hidden + min-height:0 so it actually clips during the transition (the grid child is the
|
||||
collapsing unit). visibility:hidden removes all descendants from the tab order and from pointer/
|
||||
keyboard interaction once collapsed — this fixes the Major accessibility defect where Tab could
|
||||
reach hidden controls. transition-behavior:allow-discrete makes visibility flip discretely: it
|
||||
flips to hidden AFTER the ease-out finishes (so the animation plays fully), and flips back to
|
||||
visible BEFORE the ease-in starts (so content is immediately interactive on the way back in).
|
||||
The visibility transition is listed as 0s so it is instant when it fires; the allow-discrete
|
||||
behaviour determines which end of the transition that instant flip occurs on. */
|
||||
.dd-theater-collapsible {
|
||||
overflow: hidden;
|
||||
max-height: 400vh;
|
||||
display: grid;
|
||||
grid-template-rows: 1fr;
|
||||
opacity: 1;
|
||||
transition: max-height 0.45s ease, opacity 0.3s ease;
|
||||
visibility: visible;
|
||||
transition: grid-template-rows 0.45s ease, opacity 0.3s ease, visibility 0s;
|
||||
transition-behavior: allow-discrete;
|
||||
}
|
||||
|
||||
/* The single direct child clips itself during the grid-row collapse. min-height:0 overrides the
|
||||
implicit min-height:auto that would prevent the row from shrinking past the content's intrinsic
|
||||
height. overflow:hidden clips painted content when the row is partially collapsed. */
|
||||
.dd-theater-collapsible > * {
|
||||
overflow: hidden;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.dd-theater-collapsed {
|
||||
max-height: 0;
|
||||
grid-template-rows: 0fr;
|
||||
opacity: 0;
|
||||
/* visibility flips to hidden instantly, but allow-discrete defers it to AFTER the ease-out
|
||||
completes (at the end of the 0.45s transition), so the animation still plays in full. */
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
/* Honor reduced-motion: collapse still happens (it is layout, not decoration) but instantly, matching
|
||||
|
||||
Reference in New Issue
Block a user