fix(popover): stop animating left/top so first open doesn't slide from corner
Workflow / build (pull_request) Successful in 1m18s
Workflow / e2e (pull_request) Successful in 1m15s
Workflow / publish (pull_request) Has been skipped

This commit is contained in:
Ilia Mashkov
2026-06-02 21:38:48 +03:00
parent a8a985ee6a
commit cbd95350bb
+12 -4
View File
@@ -88,6 +88,14 @@ let resolvedSide = $state(side);
*/
let positioned = $state(false);
/**
* Resolved fixed-position coordinates. Applied through the reactive `style`
* attribute (not imperatively) so they can't be wiped when the attribute
* re-renders — mixing the two caused a one-frame top-left flash.
*/
let x = $state(0);
let y = $state(0);
/**
* Actual DOM open state, driven by the `toggle` event. Source of truth for
* whether the browser currently shows the popover; `open` is the public binding.
@@ -132,8 +140,8 @@ function updatePosition(): void {
sideOffset,
});
resolvedSide = result.side;
contentEl.style.left = `${result.x}px`;
contentEl.style.top = `${result.y}px`;
x = result.x;
y = result.y;
positioned = true;
}
@@ -204,9 +212,9 @@ $effect(() => {
data-side={resolvedSide}
data-state={shown ? 'open' : 'closed'}
ontoggle={onToggle}
style={`position: fixed; inset: auto; margin: 0;${positioned ? '' : ' visibility: hidden;'}`}
style={`position: fixed; inset: auto; left: ${x}px; top: ${y}px; margin: 0;${positioned ? '' : ' visibility: hidden;'}`}
class={cn(
'opacity-0 scale-95 transition-discrete transition-all duration-fast',
'opacity-0 scale-95 transition-discrete transition-[opacity,transform] duration-fast',
'starting:opacity-0 starting:scale-95',
'[&:popover-open]:opacity-100 [&:popover-open]:scale-100',
'data-[side=top]:origin-bottom data-[side=bottom]:origin-top',