Feature/popover #48
@@ -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',
|
||||
|
||||
Reference in New Issue
Block a user