Skip to content

Commit 330753a

Browse files
zernoniaclaude
andcommitted
fix(Drawer): snap story enter animation clobbers snap-point transform
Problem: when the drawer opens at snap=0.5, the CSS keyframe animation `drawer-slide-bottom-in` was animating the `transform` property from translateY(100%) to translateY(0). Because `transform` is the same CSS property used to apply the snap-point offset, the keyframe clobbered the inline transform for the full 450ms of the enter animation. The drawer slid in all the way to translateY(0) (snap=1.0), then the animation ended and the inline transform reasserted, snapping the drawer down to translateY(400) (snap=0.5). Visible as a brief "slide past 50% then drop back" flicker. Fix: switch the snap-points drawer to a dedicated `drawer-snap-slide-in` / `drawer-snap-slide-out` pair keyed on the independent `translate` CSS property instead of `transform`. `translate` and `transform` are composable: the keyframe animates `translate: 0 100dvh -> 0 0` while the inline `transform: translateY(calc(snap-offset + swipe-y))` stays applied throughout. Enter/exit now slide from below the viewport up to the active snap point in a single continuous motion. Only the snap-points drawer needs this; the regular bottom/top/left/ right variants keep the original `transform`-keyframe animations because they have no snap-point offset to preserve. Verified in histoire: open at 0.5 slides in to 50%, Snap 100% expands smoothly via inline transform transition, Snap 50% returns smoothly, Close slides off-screen. 32/32 tests still passing. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 745b3a0 commit 330753a

File tree

1 file changed

+16
-3
lines changed

1 file changed

+16
-3
lines changed

packages/core/src/Drawer/story/Drawer.story.vue

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -473,6 +473,13 @@ const navLinks = [
473473
* then the snap-point-offset transform slides the popup down to visually
474474
* reveal only the active snap point's portion. Ported from BaseUI's
475475
* snap-points demo CSS.
476+
*
477+
* Enter/exit animations use the independent `translate` CSS property so
478+
* they compose with the inline `transform` (which carries the snap point
479+
* offset) instead of replacing it. If we used `transform` in the keyframes,
480+
* the enter animation would clobber the snap-point transform and the drawer
481+
* would briefly slide up to fully-open (snap 1.0) before settling at the
482+
* active snap point — a visible flicker.
476483
*/
477484
.drawer-content-snap {
478485
position: fixed;
@@ -489,19 +496,25 @@ const navLinks = [
489496
overflow: visible;
490497
transform: translateY(calc(var(--drawer-snap-point-offset, 0px) + var(--drawer-swipe-movement-y, 0px)));
491498
transition: transform 450ms cubic-bezier(0.32, 0.72, 0, 1);
492-
will-change: transform;
499+
will-change: transform, translate;
493500
}
494501
.drawer-content-snap[data-state="open"] {
495-
animation: drawer-slide-bottom-in 450ms cubic-bezier(0.32, 0.72, 0, 1);
502+
animation: drawer-snap-slide-in 450ms cubic-bezier(0.32, 0.72, 0, 1);
496503
}
497504
.drawer-content-snap[data-state="closed"] {
498-
animation: drawer-slide-bottom-out 450ms cubic-bezier(0.32, 0.72, 0, 1);
505+
animation: drawer-snap-slide-out 450ms cubic-bezier(0.32, 0.72, 0, 1);
499506
}
500507
.drawer-content-snap[data-swiping] {
501508
animation: none;
502509
transition-duration: 0ms;
503510
user-select: none;
504511
}
512+
@keyframes drawer-snap-slide-in {
513+
from { translate: 0 100dvh; }
514+
}
515+
@keyframes drawer-snap-slide-out {
516+
to { translate: 0 100dvh; }
517+
}
505518
.drawer-snap-handle {
506519
flex-shrink: 0;
507520
}

0 commit comments

Comments
 (0)