Skip to content

Commit 4d8cfb8

Browse files
authored
fix(floating-ui): improve floating element performance (#8409)
**Related Issue:** #7979 #8214 #8386 #8419 #5697 ## Summary - reverts #8001 - Keeps doc updates - reverts partially #8230 - Keeps drag classes that are setting `overflow:hidden` when a drag is occurring. - Keeps roundByDPR floating-ui fix. https://floating-ui.com/docs/misc#subpixel-and-accelerated-positioning - Hides overflow for `calcite-sortable--chosen` class - Only sets `top` and `left` on floating element once positioned. **This fixes native drag and drop issue**
1 parent 509c9f1 commit 4d8cfb8

File tree

10 files changed

+43
-24
lines changed

10 files changed

+43
-24
lines changed

packages/calcite-components/src/assets/styles/_sortable.scss

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
@mixin sortable-helper-classes() {
2+
.calcite-sortable--chosen,
23
.calcite-sortable--ghost,
34
.calcite-sortable--drag {
45
overflow: hidden;

packages/calcite-components/src/components.d.ts

+10
Original file line numberDiff line numberDiff line change
@@ -6260,6 +6260,8 @@ declare global {
62606260
};
62616261
interface HTMLCalciteListElementEventMap {
62626262
"calciteListChange": void;
6263+
"calciteListDragEnd": ListDragDetail;
6264+
"calciteListDragStart": ListDragDetail;
62636265
"calciteListFilter": void;
62646266
"calciteListOrderChange": ListDragDetail;
62656267
"calciteInternalListDefaultSlotChange": void;
@@ -9984,6 +9986,14 @@ declare namespace LocalJSX {
99849986
* Emits when any of the list item selections have changed.
99859987
*/
99869988
"onCalciteListChange"?: (event: CalciteListCustomEvent<void>) => void;
9989+
/**
9990+
* Emits when the component's dragging has ended.
9991+
*/
9992+
"onCalciteListDragEnd"?: (event: CalciteListCustomEvent<ListDragDetail>) => void;
9993+
/**
9994+
* Emits when the component's dragging has started.
9995+
*/
9996+
"onCalciteListDragStart"?: (event: CalciteListCustomEvent<ListDragDetail>) => void;
99879997
/**
99889998
* Emits when the component's filter has changed.
99899999
*/

packages/calcite-components/src/components/dropdown/dropdown.tsx

+5-5
Original file line numberDiff line numberDiff line change
@@ -78,12 +78,14 @@ export class Dropdown
7878

7979
@Watch("open")
8080
openHandler(): void {
81-
if (!this.disabled) {
82-
onToggleOpenCloseComponent(this);
81+
onToggleOpenCloseComponent(this);
82+
83+
if (this.disabled) {
84+
this.open = false;
8385
return;
8486
}
8587

86-
this.open = false;
88+
this.reposition(true);
8789
}
8890

8991
/**
@@ -549,7 +551,6 @@ export class Dropdown
549551
};
550552

551553
onBeforeOpen(): void {
552-
this.reposition(true);
553554
this.calciteDropdownBeforeOpen.emit();
554555
}
555556

@@ -563,7 +564,6 @@ export class Dropdown
563564

564565
onClose(): void {
565566
this.calciteDropdownClose.emit();
566-
this.reposition(true);
567567
}
568568

569569
setReferenceEl = (el: HTMLDivElement): void => {

packages/calcite-components/src/components/input-date-picker/input-date-picker.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,8 @@ export class InputDatePicker
264264
this.open = false;
265265
return;
266266
}
267+
268+
this.reposition(true);
267269
}
268270

269271
/**
@@ -766,7 +768,6 @@ export class InputDatePicker
766768
}
767769

768770
onBeforeOpen(): void {
769-
this.reposition(true);
770771
this.calciteInputDatePickerBeforeOpen.emit();
771772
}
772773

@@ -792,7 +793,6 @@ export class InputDatePicker
792793
this.restoreInputFocus();
793794
this.focusOnOpen = false;
794795
this.datePickerEl.reset();
795-
this.reposition(true);
796796
}
797797

798798
setStartInput = (el: HTMLCalciteInputElement): void => {

packages/calcite-components/src/components/input-time-picker/input-time-picker.tsx

+3-4
Original file line numberDiff line numberDiff line change
@@ -172,16 +172,15 @@ export class InputTimePicker
172172
@Prop({ reflect: true, mutable: true }) open = false;
173173

174174
@Watch("open")
175-
openHandler(open: boolean): void {
175+
openHandler(): void {
176176
onToggleOpenCloseComponent(this);
177+
177178
if (this.disabled || this.readOnly) {
178179
this.open = false;
179180
return;
180181
}
181182

182-
if (open) {
183-
this.reposition(true);
184-
}
183+
this.reposition(true);
185184
}
186185

187186
/** When `true`, interaction is prevented and the component is displayed with lower opacity. */

packages/calcite-components/src/components/popover/popover.tsx

+1-3
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ export class Popover
194194
@Watch("open")
195195
openHandler(): void {
196196
onToggleOpenCloseComponent(this);
197-
197+
this.reposition(true);
198198
this.setExpandedAttr();
199199
}
200200

@@ -499,7 +499,6 @@ export class Popover
499499
};
500500

501501
onBeforeOpen(): void {
502-
this.reposition(true);
503502
this.calcitePopoverBeforeOpen.emit();
504503
}
505504

@@ -515,7 +514,6 @@ export class Popover
515514
onClose(): void {
516515
this.calcitePopoverClose.emit();
517516
deactivateFocusTrap(this);
518-
this.reposition(true);
519517
}
520518

521519
storeArrowEl = (el: SVGElement): void => {

packages/calcite-components/src/components/tooltip/tooltip.tsx

+1-2
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ export class Tooltip implements FloatingUIComponent, OpenCloseComponent {
8989
@Watch("open")
9090
openHandler(): void {
9191
onToggleOpenCloseComponent(this);
92+
this.reposition(true);
9293
}
9394

9495
/**
@@ -249,7 +250,6 @@ export class Tooltip implements FloatingUIComponent, OpenCloseComponent {
249250
// --------------------------------------------------------------------------
250251

251252
onBeforeOpen(): void {
252-
this.reposition(true);
253253
this.calciteTooltipBeforeOpen.emit();
254254
}
255255

@@ -263,7 +263,6 @@ export class Tooltip implements FloatingUIComponent, OpenCloseComponent {
263263

264264
onClose(): void {
265265
this.calciteTooltipClose.emit();
266-
this.reposition(true);
267266
}
268267

269268
private setTransitionEl = (el): void => {

packages/calcite-components/src/tests/commonTests.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1352,7 +1352,7 @@ export function floatingUIOwner(
13521352
await scrollTo(scrollablePageSizeInPx, scrollablePageSizeInPx);
13531353
await page.waitForChanges();
13541354

1355-
expect(await getTransform()).not.toBe(initialClosedTransform);
1355+
expect(await getTransform()).toBe(initialClosedTransform);
13561356

13571357
await scrollTo(0, 0);
13581358
await page.waitForChanges();

packages/calcite-components/src/utils/floating-ui.spec.ts

+13-3
Original file line numberDiff line numberDiff line change
@@ -80,24 +80,34 @@ describe("repositioning", () => {
8080
expect(floatingEl.style.left).toBe("0");
8181
}
8282

83-
it("repositions immediately by default", async () => {
83+
it("repositions only for open components", async () => {
84+
await reposition(fakeFloatingUiComponent, positionOptions);
8485
assertPreOpenPositioning(floatingEl);
8586

8687
fakeFloatingUiComponent.open = true;
8788

89+
await reposition(fakeFloatingUiComponent, positionOptions);
90+
assertOpenPositioning(floatingEl);
91+
});
92+
93+
it("repositions immediately by default", async () => {
94+
fakeFloatingUiComponent.open = true;
95+
8896
reposition(fakeFloatingUiComponent, positionOptions);
8997

98+
assertPreOpenPositioning(floatingEl);
99+
90100
await waitForAnimationFrame();
91101
assertOpenPositioning(floatingEl);
92102
});
93103

94104
it("can reposition after a delay", async () => {
95-
assertPreOpenPositioning(floatingEl);
96-
97105
fakeFloatingUiComponent.open = true;
98106

99107
reposition(fakeFloatingUiComponent, positionOptions, true);
100108

109+
assertPreOpenPositioning(floatingEl);
110+
101111
await new Promise<void>((resolve) => setTimeout(resolve, repositionDebounceTimeout));
102112
assertOpenPositioning(floatingEl);
103113
});

packages/calcite-components/src/utils/floating-ui.ts

+6-4
Original file line numberDiff line numberDiff line change
@@ -157,8 +157,8 @@ export const positionFloatingUI =
157157
pointerEvents,
158158
position,
159159
transform: open ? `translate(${roundByDPR(x)}px,${roundByDPR(y)}px)` : "",
160-
left: open ? "0" : "",
161-
top: open ? "0" : "",
160+
top: 0,
161+
left: 0,
162162
});
163163
};
164164

@@ -427,6 +427,10 @@ export async function reposition(
427427
options: Parameters<typeof positionFloatingUI>[1],
428428
delayed = false
429429
): Promise<void> {
430+
if (!component.open) {
431+
return;
432+
}
433+
430434
const positionFunction = delayed ? getDebouncedReposition(component) : positionFloatingUI;
431435

432436
return positionFunction(component, options);
@@ -489,8 +493,6 @@ export function connectFloatingUI(
489493

490494
// initial positioning based on https://floating-ui.com/docs/computePosition#initial-layout
491495
position: component.overlayPositioning,
492-
top: "0",
493-
left: "0",
494496
});
495497

496498
const runAutoUpdate = Build.isBrowser

0 commit comments

Comments
 (0)