Skip to content

Commit 7a6633a

Browse files
authored
Merge pull request #5126 from cardstack/fix-adorn-label-tab-position-flash
Compute the hover overlay position from live rects (fix first-frame jump)
2 parents 1e9229c + ce1369d commit 7a6633a

1 file changed

Lines changed: 37 additions & 6 deletions

File tree

packages/host/app/components/operator-mode/overlays.gts

Lines changed: 37 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -126,22 +126,53 @@ export default class Overlays extends Component<OverlaySignature> {
126126
protected offset = {
127127
name: 'offset',
128128
fn: (state: MiddlewareState) => {
129-
let { elements, rects } = state;
129+
let { elements } = state;
130130
let { floating, reference } = elements;
131-
let { width, height } = reference.getBoundingClientRect();
131+
let refRect = reference.getBoundingClientRect();
132132

133-
floating.style.width = width + 'px';
134-
floating.style.height = height + 'px';
133+
floating.style.width = refRect.width + 'px';
134+
floating.style.height = refRect.height + 'px';
135135
floating.style.position = 'absolute';
136136
// Mirror the underlying card's corner radius so any decorative
137137
// outline / box-shadow on the overlay follows the same curve.
138138
if (reference instanceof Element) {
139139
floating.style.borderRadius =
140140
window.getComputedStyle(reference).borderRadius;
141141
}
142+
143+
// Position the overlay from the live reference rect relative to the
144+
// floating element's own offset parent, rather than floating-ui's
145+
// `rects.reference`. floating-ui's first one-or-two computePosition calls
146+
// omit the offset parent's offset (they return the reference in viewport
147+
// coordinates and only subtract the offset parent a frame later), so
148+
// trusting `rects.reference` makes the overlay — and everything riding it
149+
// (the type-label tab, the select chip, the menu, the outline) — paint
150+
// one frame off and visibly jump into place on first appearance.
151+
// Computing it ourselves from the current rects is correct on the very
152+
// first frame. We recover the offset parent's scale the same way the
153+
// Adorn label positioner does (the test runner scales `#ember-testing`),
154+
// and convert the viewport anchor into the offset parent's local space.
155+
let offsetParent = floating.offsetParent as HTMLElement | null;
156+
let parentRect = offsetParent
157+
? offsetParent.getBoundingClientRect()
158+
: new DOMRect(0, 0, window.innerWidth, window.innerHeight);
159+
let scaleX =
160+
offsetParent && offsetParent.offsetWidth > 0
161+
? parentRect.width / offsetParent.offsetWidth
162+
: 1;
163+
let scaleY =
164+
offsetParent && offsetParent.offsetHeight > 0
165+
? parentRect.height / offsetParent.offsetHeight
166+
: 1;
167+
if (!Number.isFinite(scaleX) || scaleX === 0) {
168+
scaleX = 1;
169+
}
170+
if (!Number.isFinite(scaleY) || scaleY === 0) {
171+
scaleY = 1;
172+
}
142173
return {
143-
x: rects.reference.x,
144-
y: rects.reference.y,
174+
x: (refRect.left - parentRect.left) / scaleX,
175+
y: (refRect.top - parentRect.top) / scaleY,
145176
};
146177
},
147178
};

0 commit comments

Comments
 (0)