Skip to content

Commit

Permalink
fix(select): port fixed positioning fixes back from v6.0.0
Browse files Browse the repository at this point in the history
This fixes an issue where the bottom of the listbox is below the
viewport bottom. Also added the `positionOptions` prop to the Select to
further customize the positioning.

Closes #1461
  • Loading branch information
mlaursen committed Dec 11, 2023
1 parent da44bbd commit feb9ec6
Show file tree
Hide file tree
Showing 16 changed files with 704 additions and 245 deletions.
Expand Up @@ -5,7 +5,7 @@ exports[`AutoComplete should be able to render content before and after the matc
class="rmd-list rmd-listbox rmd-listbox--temporary rmd-transition--scale-y-enter rmd-transition--scale-y-enter-active"
id="autocomplete-listbox"
role="listbox"
style="left: 0px; top: 0px; width: 0px; position: fixed; transform-origin: 50% 0;"
style="position: fixed; transform-origin: 50% 0; left: 0px; top: 0px; width: 0px;"
>
<div>
Before Results
Expand Down Expand Up @@ -76,7 +76,7 @@ exports[`AutoComplete should be able to render content before and after the matc
class="rmd-list rmd-listbox rmd-listbox--temporary rmd-transition--scale-y-enter rmd-transition--scale-y-enter-active"
id="autocomplete-listbox"
role="listbox"
style="left: 0px; top: 0px; width: 0px; position: fixed; transform-origin: 50% 0;"
style="position: fixed; transform-origin: 50% 0; left: 0px; top: 0px; width: 0px;"
>
<div>
Before Results
Expand Down Expand Up @@ -147,7 +147,7 @@ exports[`AutoComplete should be able to render content before and after the matc
class="rmd-list rmd-listbox rmd-listbox--temporary rmd-transition--scale-y-enter rmd-transition--scale-y-enter-active"
id="autocomplete-listbox"
role="listbox"
style="left: 0px; top: 0px; width: 0px; position: fixed; transform-origin: 50% 0;"
style="position: fixed; transform-origin: 50% 0; left: 0px; top: 0px; width: 0px;"
>
<div>
Before Results
Expand Down Expand Up @@ -238,7 +238,7 @@ exports[`AutoComplete should handle a normal filter flow 1`] = `
class="rmd-list rmd-listbox rmd-listbox--temporary rmd-transition--scale-y-enter rmd-transition--scale-y-enter-active"
id="autocomplete-listbox"
role="listbox"
style="left: 0px; top: 0px; width: 0px; position: fixed; transform-origin: 50% 0;"
style="position: fixed; transform-origin: 50% 0; left: 0px; top: 0px; width: 0px;"
>
<li
class="rmd-list-item rmd-list-item--clickable rmd-option"
Expand Down
Expand Up @@ -20,6 +20,7 @@ exports[`FixedDialog should disable the overlay and scroll lock behavior by defa
class="rmd-dialog rmd-dialog--fixed"
id="dialog"
role="dialog"
style="position: fixed; transform-origin: 100% 0;"
tabindex="-1"
/>
</body>
Expand Down
Expand Up @@ -6,7 +6,7 @@ exports[`MenuItemFileInput should call the onClick handlers correctly 1`] = `
class="rmd-menu rmd-menu--elevated"
id="dropdown-menu-menu"
role="menu"
style="left: 16px; top: 0px; position: fixed; transform-origin: 0 0;"
style="position: fixed; transform-origin: 0 0; left: 16px; top: 0px;"
tabindex="-1"
>
<ul
Expand Down Expand Up @@ -50,7 +50,7 @@ exports[`MenuItemFileInput should work correctly 1`] = `
class="rmd-menu rmd-menu--elevated"
id="dropdown-menu-menu"
role="menu"
style="left: 16px; top: 0px; position: fixed; transform-origin: 0 0;"
style="position: fixed; transform-origin: 0 0; left: 16px; top: 0px;"
tabindex="-1"
>
<ul
Expand Down
Expand Up @@ -6,7 +6,7 @@ exports[`MenuItemTextField should not change the menu's keyboard focus behavior
class="rmd-menu rmd-menu--elevated"
id="dropdown-menu-menu"
role="menu"
style="left: 16px; top: 0px; position: fixed; transform-origin: 0 0;"
style="position: fixed; transform-origin: 0 0; left: 16px; top: 0px;"
tabindex="-1"
>
<ul
Expand Down
22 changes: 21 additions & 1 deletion packages/form/src/select/Select.tsx
Expand Up @@ -4,7 +4,11 @@ import cn from "classnames";
import { useIcon } from "@react-md/icon";
import type { ListElement } from "@react-md/list";
import { useFixedPositioning } from "@react-md/transition";
import type { PositionAnchor, PositionWidth } from "@react-md/utils";
import type {
CalculateFixedPositionOptions,
PositionAnchor,
PositionWidth,
} from "@react-md/utils";
import {
BELOW_CENTER_ANCHOR,
bem,
Expand Down Expand Up @@ -154,6 +158,20 @@ export interface SelectProps
* `@react-md/icon` package.
*/
rightChildren?: ReactNode;

/**
* Used to add any additional fixed positioning behavior.
* @example
* ```tsx
* positionOptions={{
* preventOverlap: true,
* disableSwapping: true,
* }}
* ```
*
* @remarks \@since 5.1.6
*/
positionOptions?: CalculateFixedPositionOptions;
}

const block = bem("rmd-select");
Expand Down Expand Up @@ -196,6 +214,7 @@ export const Select = forwardRef<HTMLDivElement, SelectProps>(function Select(
isRightAddon = true,
underlineDirection: propUnderlineDirection,
listboxWidth = "equal",
positionOptions,
portal = true,
portalInto,
portalIntoId,
Expand Down Expand Up @@ -293,6 +312,7 @@ export const Select = forwardRef<HTMLDivElement, SelectProps>(function Select(
onResize: closeOnResize ? hide : undefined,
transformOrigin: true,
width: listboxWidth,
...positionOptions,
onEntering() {
// can't do onEnter since the positioning styles haven't been applied to the
// dom node at this time. this means the list is the last element in the DOM
Expand Down
24 changes: 12 additions & 12 deletions packages/menu/src/__tests__/__snapshots__/MenuBar.tsx.snap
Expand Up @@ -112,7 +112,7 @@ exports[`MenuBar hover mode should allow for a click-first hover mode 1`] = `
class="rmd-menu rmd-menu--elevated"
id="menu-1-menu"
role="menu"
style="left: 16px; top: 0px; position: fixed; transform-origin: 0 0;"
style="position: fixed; transform-origin: 0 0; left: 16px; top: 0px;"
tabindex="-1"
>
<ul
Expand Down Expand Up @@ -273,7 +273,7 @@ exports[`MenuBar hover mode should allow for a click-first hover mode 2`] = `
class="rmd-menu rmd-menu--elevated"
id="menu-1-menu"
role="menu"
style="left: 16px; top: 0px; position: fixed; transform-origin: 0 0;"
style="position: fixed; transform-origin: 0 0; left: 16px; top: 0px;"
tabindex="-1"
>
<ul
Expand Down Expand Up @@ -434,7 +434,7 @@ exports[`MenuBar hover mode should allow for a click-first hover mode 3`] = `
class="rmd-menu rmd-menu--elevated"
id="menu-2-menu"
role="menu"
style="left: 16px; top: 0px; position: fixed; transform-origin: 0 0;"
style="position: fixed; transform-origin: 0 0; left: 16px; top: 0px;"
tabindex="-1"
>
<ul
Expand Down Expand Up @@ -581,7 +581,7 @@ exports[`MenuBar hover mode should allow for a click-first hover mode 4`] = `
class="rmd-menu rmd-menu--elevated"
id="menu-2-menu"
role="menu"
style="left: 16px; top: 0px; position: fixed; transform-origin: 0 0;"
style="position: fixed; transform-origin: 0 0; left: 16px; top: 0px;"
tabindex="-1"
>
<ul
Expand Down Expand Up @@ -728,7 +728,7 @@ exports[`MenuBar hover mode should allow for an immediate hover mode by setting
class="rmd-menu rmd-menu--elevated rmd-transition--scale-y-enter rmd-transition--scale-y-enter-active"
id="menu-1-menu"
role="menu"
style="left: 16px; top: 0px; position: fixed; transform-origin: 0 0;"
style="position: fixed; transform-origin: 0 0; left: 16px; top: 0px;"
tabindex="-1"
>
<ul
Expand Down Expand Up @@ -889,7 +889,7 @@ exports[`MenuBar hover mode should allow for an immediate hover mode by setting
class="rmd-menu rmd-menu--elevated"
id="menu-1-menu"
role="menu"
style="left: 16px; top: 0px; position: fixed; transform-origin: 0 0;"
style="position: fixed; transform-origin: 0 0; left: 16px; top: 0px;"
tabindex="-1"
>
<ul
Expand Down Expand Up @@ -1050,7 +1050,7 @@ exports[`MenuBar hover mode should allow for an immediate hover mode by setting
class="rmd-menu rmd-menu--elevated"
id="menu-4-menu"
role="menu"
style="left: 16px; top: 0px; position: fixed; transform-origin: 0 0;"
style="position: fixed; transform-origin: 0 0; left: 16px; top: 0px;"
tabindex="-1"
>
<ul
Expand Down Expand Up @@ -1219,7 +1219,7 @@ exports[`MenuBar hover mode should allow for an immediate hover mode by setting
class="rmd-menu rmd-menu--elevated"
id="menu-4-menu"
role="menu"
style="left: 16px; top: 0px; position: fixed; transform-origin: 0 0;"
style="position: fixed; transform-origin: 0 0; left: 16px; top: 0px;"
tabindex="-1"
>
<ul
Expand Down Expand Up @@ -1388,7 +1388,7 @@ exports[`MenuBar hover mode should allow for an immediate hover mode by setting
class="rmd-menu rmd-menu--elevated"
id="menu-4-menu"
role="menu"
style="left: 16px; top: 0px; position: fixed; transform-origin: 0 0;"
style="position: fixed; transform-origin: 0 0; left: 16px; top: 0px;"
tabindex="-1"
>
<ul
Expand Down Expand Up @@ -1453,7 +1453,7 @@ exports[`MenuBar hover mode should allow for an immediate hover mode by setting
class="rmd-menu rmd-menu--elevated"
id="submenu-1-menu"
role="menu"
style="left: 0px; top: 16px; position: fixed; transform-origin: 0 50%;"
style="position: fixed; transform-origin: 0 50%; left: 0px; top: 16px;"
tabindex="-1"
>
<ul
Expand Down Expand Up @@ -1628,7 +1628,7 @@ exports[`MenuBar hover mode should allow for an immediate hover mode by setting
class="rmd-menu rmd-menu--elevated"
id="menu-4-menu"
role="menu"
style="left: 16px; top: 0px; position: fixed; transform-origin: 0 0;"
style="position: fixed; transform-origin: 0 0; left: 16px; top: 0px;"
tabindex="-1"
>
<ul
Expand Down Expand Up @@ -1693,7 +1693,7 @@ exports[`MenuBar hover mode should allow for an immediate hover mode by setting
class="rmd-menu rmd-menu--elevated"
id="submenu-1-menu"
role="menu"
style="left: 0px; top: 16px; position: fixed; transform-origin: 0 50%;"
style="position: fixed; transform-origin: 0 50%; left: 0px; top: 16px;"
tabindex="-1"
>
<ul
Expand Down
Expand Up @@ -9,7 +9,7 @@ exports[`useFixedPositioning should allow for configuring the fixed position 1`]
</button>
<div
data-testid="element"
style="left: 16px; top: 0px; position: fixed; transform-origin: 0 0;"
style="position: fixed; transform-origin: 0 0; left: 16px; top: 0px;"
>
Some content.
</div>
Expand All @@ -36,7 +36,7 @@ exports[`useFixedPositioning should default to fixing itself with the BELOW_CENT
<div
class="rmd-transition--scale-enter rmd-transition--scale-enter-active"
data-testid="element"
style="left: 16px; top: 0px; position: fixed;"
style="position: fixed; left: 16px; top: 0px;"
>
Some content.
</div>
Expand All @@ -52,7 +52,7 @@ exports[`useFixedPositioning should default to fixing itself with the BELOW_CENT
</button>
<div
data-testid="element"
style="left: 16px; top: 0px; position: fixed;"
style="position: fixed; left: 16px; top: 0px;"
>
Some content.
</div>
Expand All @@ -69,7 +69,7 @@ exports[`useFixedPositioning should default to fixing itself with the BELOW_CENT
<div
class="rmd-transition--scale-exit rmd-transition--scale-exit-active"
data-testid="element"
style="left: 16px; top: 0px; position: fixed;"
style="position: fixed; left: 16px; top: 0px;"
>
Some content.
</div>
Expand All @@ -95,7 +95,7 @@ exports[`useFixedPositioning should update the style correctly based on the init
</button>
<div
data-testid="element"
style="left: 16px; top: 0px; position: fixed;"
style="position: fixed; left: 16px; top: 0px;"
>
Some content.
</div>
Expand All @@ -111,7 +111,7 @@ exports[`useFixedPositioning should update the style correctly based on the init
</button>
<div
data-testid="element"
style="left: 30px; top: 40px; position: fixed;"
style="position: fixed; left: 30px; top: 40px;"
>
Some content.
</div>
Expand Down
39 changes: 21 additions & 18 deletions packages/utils/src/positioning/__tests__/createHorizonalPosition.ts
@@ -1,4 +1,4 @@
import type { FixConfig } from "../createHorizontalPosition";
import type { EqualWidthOptions, FixConfig } from "../createHorizontalPosition";
import {
createAnchoredCenter,
createAnchoredInnerLeft,
Expand All @@ -8,7 +8,6 @@ import {
createEqualWidth,
createHorizontalPosition,
} from "../createHorizontalPosition";

import {
getCenterXCoord,
getInnerLeftCoord,
Expand Down Expand Up @@ -570,9 +569,8 @@ describe("createAnchoredRight", () => {
});

describe("createEqualWidth", () => {
const options1 = {
const options1: EqualWidthOptions = {
x: "center",
vw: 1000,
vwMargin: 0,
xMargin: 0,
elWidth: 200,
Expand All @@ -587,11 +585,16 @@ describe("createEqualWidth", () => {
y: 0,
toJSON() {},
},
screenRight: 1000,
isMinWidth: false,
} as const;
const options2 = { ...options1, vwMargin: 16 };
const options3 = { ...options1, xMargin: 5 };
const options4 = { ...options2, xMargin: 5 };
};
const options2: EqualWidthOptions = {
...options1,
screenRight: 984,
vwMargin: 16,
};
const options3: EqualWidthOptions = { ...options1, xMargin: 5 };
const options4: EqualWidthOptions = { ...options2, xMargin: 5 };

it("should return the width of the container element along with the left value", () => {
expect(createEqualWidth(options1)).toEqual({
Expand Down Expand Up @@ -650,26 +653,26 @@ describe("createEqualWidth", () => {
const opt4 = { ...opt2, xMargin: 5 };

expect(createEqualWidth(opt1)).toEqual({
left: 300,
minWidth: 400,
left: opt1.vwMargin,
minWidth: opt1.elWidth,
right: 0,
actualX: "center",
});
expect(createEqualWidth(opt2)).toEqual({
left: 300,
minWidth: 400,
left: opt2.vwMargin,
minWidth: opt1.elWidth,
right: 16,
actualX: "center",
});
expect(createEqualWidth(opt3)).toEqual({
left: 305,
minWidth: 390,
left: opt3.vwMargin,
minWidth: opt3.elWidth,
right: 0,
actualX: "center",
});
expect(createEqualWidth(opt4)).toEqual({
left: 305,
minWidth: 390,
left: opt4.vwMargin,
minWidth: opt4.elWidth,
right: 16,
actualX: "center",
});
Expand Down Expand Up @@ -709,8 +712,8 @@ describe("createHorizontalPosition", () => {
width: "min",
} as const;
expect(createHorizontalPosition(minWidthOptions)).toEqual({
left: containerRect1.left,
minWidth: containerRect1.width,
left: 90,
minWidth: 120,
actualX: "inner-left",
});

Expand Down

0 comments on commit feb9ec6

Please sign in to comment.