Skip to content

Commit

Permalink
fix: dragging floating ui components (#8230)
Browse files Browse the repository at this point in the history
**Related Issue:** #8214 #7979

## Summary

- Update some component `open` handlers to call reposition before open
and after open
  - Previously, they were just calling when open was set to true.
- Update `floating-ui` utility
- Handle device pixel ratio:
https://floating-ui.com/docs/misc#subpixel-and-accelerated-positioning
  - Only set `top`, `left`, and `transform` when the component is open.
- This makes it so that the positioned container is never going to "fly
in" from anywhere.
- Update sortable styles to hide any overflow on dragged elements.
  • Loading branch information
driskull committed Nov 21, 2023
1 parent d615b39 commit 5a81f6c
Show file tree
Hide file tree
Showing 8 changed files with 29 additions and 35 deletions.
5 changes: 5 additions & 0 deletions packages/calcite-components/src/assets/styles/_sortable.scss
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
@mixin sortable-helper-classes() {
.calcite-sortable--ghost,
.calcite-sortable--drag {
overflow: hidden;
}

.calcite-sortable--ghost::before {
content: "";
@apply box-border
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1211,7 +1211,7 @@ describe("calcite-dropdown", () => {
filterInput.value = "numbers";
});

expect(dropdownContentHeight.height).toBe("72px");
expect(dropdownContentHeight.height).toBe("88px");
});

describe("owns a floating-ui", () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,11 +77,8 @@ export class Dropdown
@Prop({ reflect: true, mutable: true }) open = false;

@Watch("open")
openHandler(value: boolean): void {
openHandler(): void {
if (!this.disabled) {
if (value) {
this.reposition(true);
}
onToggleOpenCloseComponent(this);
return;
}
Expand Down Expand Up @@ -207,7 +204,7 @@ export class Dropdown
this.setFilteredPlacements();
this.reposition(true);
if (this.open) {
this.openHandler(this.open);
this.openHandler();
onToggleOpenCloseComponent(this);
}
connectInteractive(this);
Expand Down Expand Up @@ -546,6 +543,7 @@ export class Dropdown
};

onBeforeOpen(): void {
this.reposition(true);
this.calciteDropdownBeforeOpen.emit();
}

Expand All @@ -559,6 +557,7 @@ export class Dropdown

onClose(): void {
this.calciteDropdownClose.emit();
this.reposition(true);
}

setReferenceEl = (el: HTMLDivElement): void => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -258,17 +258,13 @@ export class InputDatePicker
@Prop({ mutable: true, reflect: true }) open = false;

@Watch("open")
openHandler(value: boolean): void {
openHandler(): void {
onToggleOpenCloseComponent(this);

if (this.disabled || this.readOnly) {
this.open = false;
return;
}

if (value) {
this.reposition(true);
}
}

/**
Expand Down Expand Up @@ -441,7 +437,7 @@ export class InputDatePicker
connectLocalized(this);

const { open } = this;
open && this.openHandler(open);
open && this.openHandler();
if (Array.isArray(this.value)) {
this.valueAsDate = getValueAsDateRange(this.value);
} else if (this.value) {
Expand Down Expand Up @@ -766,6 +762,7 @@ export class InputDatePicker
}

onBeforeOpen(): void {
this.reposition(true);
this.calciteInputDatePickerBeforeOpen.emit();
}

Expand All @@ -791,6 +788,7 @@ export class InputDatePicker
this.restoreInputFocus();
this.focusOnOpen = false;
this.datePickerEl.reset();
this.reposition(true);
}

setStartInput = (el: HTMLCalciteInputElement): void => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -192,13 +192,9 @@ export class Popover
@Prop({ reflect: true, mutable: true }) open = false;

@Watch("open")
openHandler(value: boolean): void {
openHandler(): void {
onToggleOpenCloseComponent(this);

if (value) {
this.reposition(true);
}

this.setExpandedAttr();
}

Expand Down Expand Up @@ -502,6 +498,7 @@ export class Popover
};

onBeforeOpen(): void {
this.reposition(true);
this.calcitePopoverBeforeOpen.emit();
}

Expand All @@ -517,6 +514,7 @@ export class Popover
onClose(): void {
this.calcitePopoverClose.emit();
deactivateFocusTrap(this);
this.reposition(true);
}

storeArrowEl = (el: SVGElement): void => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,11 +87,8 @@ export class Tooltip implements FloatingUIComponent, OpenCloseComponent {
@Prop({ reflect: true }) open = false;

@Watch("open")
openHandler(value: boolean): void {
openHandler(): void {
onToggleOpenCloseComponent(this);
if (value) {
this.reposition(true);
}
}

/**
Expand Down Expand Up @@ -251,6 +248,7 @@ export class Tooltip implements FloatingUIComponent, OpenCloseComponent {
// --------------------------------------------------------------------------

onBeforeOpen(): void {
this.reposition(true);
this.calciteTooltipBeforeOpen.emit();
}

Expand All @@ -264,6 +262,7 @@ export class Tooltip implements FloatingUIComponent, OpenCloseComponent {

onClose(): void {
this.calciteTooltipClose.emit();
this.reposition(true);
}

private setTransitionEl = (el): void => {
Expand Down
10 changes: 0 additions & 10 deletions packages/calcite-components/src/utils/floating-ui.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,16 +80,6 @@ describe("repositioning", () => {
expect(floatingEl.style.left).toBe("0");
}

it("repositions for unopened components", async () => {
await reposition(fakeFloatingUiComponent, positionOptions);
assertOpenPositioning(floatingEl);

fakeFloatingUiComponent.open = true;

await reposition(fakeFloatingUiComponent, positionOptions);
assertOpenPositioning(floatingEl);
});

it("repositions immediately by default", async () => {
assertPreOpenPositioning(floatingEl);

Expand Down
13 changes: 9 additions & 4 deletions packages/calcite-components/src/utils/floating-ui.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@ import { offsetParent } from "composed-offset-position";
}
})();

function roundByDPR(value: number): number {
const dpr = window.devicePixelRatio || 1;
return Math.round(value * dpr) / dpr;
}

/**
* Positions the floating element relative to the reference element.
*
Expand Down Expand Up @@ -145,15 +150,15 @@ export const positionFloatingUI =

floatingEl.setAttribute(placementDataAttribute, effectivePlacement);

const transform = `translate(${Math.round(x)}px,${Math.round(y)}px)`;
const { open } = component;

Object.assign(floatingEl.style, {
visibility,
pointerEvents,
position,
top: "0",
left: "0",
transform,
transform: open ? `translate(${roundByDPR(x)}px,${roundByDPR(y)}px)` : "",
left: open ? "0" : "",
top: open ? "0" : "",
});
};

Expand Down

0 comments on commit 5a81f6c

Please sign in to comment.