From 78b680d444f37e21c735e94eceb03678418c9745 Mon Sep 17 00:00:00 2001 From: Matt Driscoll Date: Fri, 13 Oct 2023 10:55:49 -0700 Subject: [PATCH] fix: floating components will now get an initial position even if they are not opened (#8001) **Related Issue:** #7979 ## Summary - Removes floating-ui logic that requires a component to be open before any positioning occurs - Updates tests - commonTest - floatingUI spec test - Add jsdoc --- .../src/components/combobox/combobox.e2e.ts | 4 +- .../src/tests/commonTests.ts | 2 +- .../src/utils/floating-ui.spec.ts | 12 ++--- .../src/utils/floating-ui.ts | 45 +++++++++---------- 4 files changed, 30 insertions(+), 33 deletions(-) diff --git a/packages/calcite-components/src/components/combobox/combobox.e2e.ts b/packages/calcite-components/src/components/combobox/combobox.e2e.ts index e315419538c..ec9594ebdc8 100644 --- a/packages/calcite-components/src/components/combobox/combobox.e2e.ts +++ b/packages/calcite-components/src/components/combobox/combobox.e2e.ts @@ -1605,7 +1605,7 @@ describe("calcite-combobox", () => { it("should not focus on the combobox when items are programmatically selected", async () => { const page = await newE2EPage(); - await page.setContent(html` + await page.setContent(html` `); const item = await page.find("calcite-combobox-item"); @@ -1623,7 +1623,7 @@ describe("calcite-combobox", () => { it("should gain focus when it's items are selected via click", async () => { const page = await newE2EPage(); - await page.setContent(html` + await page.setContent(html` `); await skipAnimations(page); diff --git a/packages/calcite-components/src/tests/commonTests.ts b/packages/calcite-components/src/tests/commonTests.ts index 78c9e159537..9e6f2b19781 100644 --- a/packages/calcite-components/src/tests/commonTests.ts +++ b/packages/calcite-components/src/tests/commonTests.ts @@ -1321,7 +1321,7 @@ export function floatingUIOwner( await scrollTo(scrollablePageSizeInPx, scrollablePageSizeInPx); await page.waitForChanges(); - expect(await getTransform()).toBe(initialClosedTransform); + expect(await getTransform()).not.toBe(initialClosedTransform); await scrollTo(0, 0); await page.waitForChanges(); diff --git a/packages/calcite-components/src/utils/floating-ui.spec.ts b/packages/calcite-components/src/utils/floating-ui.spec.ts index 7d9931e33ed..e3174e94c72 100644 --- a/packages/calcite-components/src/utils/floating-ui.spec.ts +++ b/packages/calcite-components/src/utils/floating-ui.spec.ts @@ -80,9 +80,9 @@ describe("repositioning", () => { expect(floatingEl.style.left).toBe("0"); } - it("repositions only for open components", async () => { + it("repositions for unopened components", async () => { await reposition(fakeFloatingUiComponent, positionOptions); - assertPreOpenPositioning(floatingEl); + assertOpenPositioning(floatingEl); fakeFloatingUiComponent.open = true; @@ -91,23 +91,23 @@ describe("repositioning", () => { }); it("repositions immediately by default", async () => { + assertPreOpenPositioning(floatingEl); + fakeFloatingUiComponent.open = true; reposition(fakeFloatingUiComponent, positionOptions); - assertPreOpenPositioning(floatingEl); - await waitForAnimationFrame(); assertOpenPositioning(floatingEl); }); it("can reposition after a delay", async () => { + assertPreOpenPositioning(floatingEl); + fakeFloatingUiComponent.open = true; reposition(fakeFloatingUiComponent, positionOptions, true); - assertPreOpenPositioning(floatingEl); - await new Promise((resolve) => setTimeout(resolve, repositionDebounceTimeout)); assertOpenPositioning(floatingEl); }); diff --git a/packages/calcite-components/src/utils/floating-ui.ts b/packages/calcite-components/src/utils/floating-ui.ts index c3a36b2d84c..c8e371941b6 100644 --- a/packages/calcite-components/src/utils/floating-ui.ts +++ b/packages/calcite-components/src/utils/floating-ui.ts @@ -402,29 +402,26 @@ export function getEffectivePlacement(floatingEl: HTMLElement, placement: Logica * * Note: this is not needed for components that use `calcite-popover`. * - * @param component - * @param options - * @param options.referenceEl - * @param options.floatingEl - * @param options.overlayPositioning - * @param options.placement - * @param options.flipDisabled - * @param options.flipPlacements - * @param options.offsetDistance - * @param options.offsetSkidding - * @param options.arrowEl - * @param options.type - * @param delayed + * @param component - A floating-ui component. + * @param options - Reposition parameters. + * @param options.referenceEl - The `referenceElement` used to position the component according to its `placement` value. + * @param options.floatingEl - The `floatingElement` containing the floating ui. + * @param options.overlayPositioning - type of positioning to use for the overlaid content. + * @param options.placement - Determines where the component will be positioned relative to the `referenceElement`. + * @param options.flipDisabled - Prevents flipping the component's placement when overlapping its `referenceElement`. + * @param options.flipPlacements - Defines the available placements that can be used when a flip occurs. + * @param options.offsetDistance - Offsets the position of the popover away from the `referenceElement`. + * @param options.offsetSkidding - Offsets the position of the component along the `referenceElement`. + * @param options.arrowEl - A customizable arrow element. + * @param options.type - The type of floating UI. + * @param delayed - Reposition the component after a delay. + * @returns {Promise} */ export async function reposition( component: FloatingUIComponent, options: Parameters[1], delayed = false ): Promise { - if (!component.open) { - return; - } - const positionFunction = delayed ? getDebouncedReposition(component) : positionFloatingUI; return positionFunction(component, options); @@ -466,9 +463,9 @@ const componentToDebouncedRepositionMap = new WeakMap void) => { + : (_refEl: HTMLElement, _floatingEl: HTMLElement, updateCallback: () => void): (() => void) => { updateCallback(); return () => { /* noop */ @@ -509,9 +506,9 @@ export function connectFloatingUI( /** * Helper to tear down floating element interactions on disconnectedCallback. * - * @param component - * @param referenceEl - * @param floatingEl + * @param component - A floating-ui component. + * @param referenceEl - The `referenceElement` used to position the component according to its `placement` value. + * @param floatingEl - The `floatingElement` containing the floating ui. */ export function disconnectFloatingUI( component: FloatingUIComponent,