Skip to content

Commit

Permalink
revert changes to relative position
Browse files Browse the repository at this point in the history
- update react-useportal to v1.0.19
- add options to useListener
  • Loading branch information
petermakowski committed Nov 27, 2023
1 parent 099f674 commit f2f830c
Show file tree
Hide file tree
Showing 7 changed files with 238 additions and 127 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@
"prop-types": "15.8.1",
"react-router-dom": "6.17.0",
"react-table": "7.8.0",
"react-useportal": "1.0.18"
"react-useportal": "1.0.19"
},
"resolutions": {
"@types/react": "18.2.28",
Expand Down
28 changes: 19 additions & 9 deletions src/components/ContextualMenu/ContextualMenu.stories.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,23 @@ import ContextualMenu from "./ContextualMenu";
/>

export const ScrollTemplate = (args) => (
<div style={{ maxWidth: "30rem", maxHeight: "10rem", overflow: "auto", padding: "1rem" }}>
<div
style={{
maxWidth: "30rem",
maxHeight: "10rem",
overflow: "auto",
padding: "1rem",
}}
>
<ContextualMenu {...args} />
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit.
Consequuntur cum dicta beatae nostrum eligendi similique
earum, dolorem fuga quis, sequi voluptates architecto ipsa
dolorum eaque rem expedita inventore voluptas odit
aspernatur alias molestias facere.</p>
{Array(3).fill(
<p>
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Consequuntur
cum dicta beatae nostrum eligendi similique earum, dolorem fuga quis,
sequi voluptates architecto ipsa dolorum eaque rem expedita inventore
voluptas odit aspernatur alias molestias facere.
</p>
)}
</div>
);

Expand Down Expand Up @@ -99,11 +109,11 @@ The contextual menu will provide a visual wrapper to any provided children. Visi
links: [
{
children: "Link 1",
onClick: () => { },
onClick: () => {},
},
{
children: "Long Link 2",
onClick: () => { },
onClick: () => {},
},
],
hasToggleIcon: true,
Expand All @@ -112,7 +122,7 @@ The contextual menu will provide a visual wrapper to any provided children. Visi
}}
>
{ScrollTemplate.bind({})}
</Story>
</Story>
</Canvas>

### Child function
Expand Down
137 changes: 80 additions & 57 deletions src/components/ContextualMenu/ContextualMenu.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import classNames from "classnames";
import React, { useCallback, useEffect, useRef, useState } from "react";
import type { HTMLProps } from "react";
import usePortal from "react-useportal";

import { useListener, useOnEscapePressed, usePrevious } from "hooks";
import { useListener, usePrevious } from "hooks";
import Button from "../Button";
import type { ButtonProps } from "../Button";
import ContextualMenuDropdown from "./ContextualMenuDropdown";
import type { ContextualMenuDropdownProps } from "./ContextualMenuDropdown";
import type { MenuLink, Position } from "./ContextualMenuDropdown";
import { ClassName, PropsWithSpread, SubComponentProps } from "types";
import { useId } from "hooks/useId";
import { useOnClickOutside } from "hooks/useOnClickOutside";

export enum Label {
Toggle = "Toggle menu",
Expand Down Expand Up @@ -206,19 +206,21 @@ const ContextualMenu = <L,>({
setPositionCoords(parent.getBoundingClientRect());
}, [wrapper, positionNode]);

const [isOpen, setIsOpen] = useState(visible);
const handleOpen = useCallback(() => {
// Call the toggle callback, if supplied.
onToggleMenu && onToggleMenu(true);
// When the menu opens then update the coordinates of the parent.
updatePositionCoords();
setIsOpen(true);
}, [onToggleMenu, updatePositionCoords]);
const handleClose = useCallback(() => {
// Call the toggle callback, if supplied.
onToggleMenu && onToggleMenu(false);
setIsOpen(false);
}, [onToggleMenu]);
const { openPortal, closePortal, isOpen, Portal } = usePortal({
closeOnEsc,
closeOnOutsideClick,
isOpen: visible,
onOpen: () => {
// Call the toggle callback, if supplied.
onToggleMenu && onToggleMenu(true);
// When the menu opens then update the coordinates of the parent.
updatePositionCoords();
},
onClose: () => {
// Call the toggle callback, if supplied.
onToggleMenu && onToggleMenu(false);
},
});

const previousVisible = usePrevious(visible);
const labelNode =
Expand All @@ -227,7 +229,7 @@ const ContextualMenu = <L,>({
) : React.isValidElement(toggleLabel) ? (
toggleLabel
) : null;
const wrapperClass = classNames(className, "p-contextual-menu", {
const contextualMenuClassName = classNames(className, "p-contextual-menu", {
[`p-contextual-menu--${adjustedPosition}`]: adjustedPosition !== "right",
});

Expand All @@ -249,36 +251,54 @@ const ContextualMenu = <L,>({
useEffect(() => {
if (visible !== previousVisible) {
if (visible && !isOpen) {
handleOpen();
openPortal();
} else if (!visible && isOpen) {
handleClose();
closePortal();
}
}
}, [handleClose, handleOpen, visible, isOpen, previousVisible]);
}, [closePortal, openPortal, visible, isOpen, previousVisible]);

useOnClickOutside(wrapper, handleClose, {
isEnabled: closeOnOutsideClick,
});
useOnEscapePressed(handleClose, { isEnabled: closeOnEsc });
const onResize = useCallback(
(evt) => {
console.log("on resize!");
const parent = getPositionNode(wrapper.current, positionNode);
if (parent && !getPositionNodeVisible(parent)) {
// Hide the menu if the item has become hidden. This might happen in
// a responsive table when columns become hidden as the page
// becomes smaller.
closePortal(evt);
} else {
// Update the coordinates so that the menu stays relative to the
// toggle button.
updatePositionCoords();
}
},
[closePortal, positionNode, updatePositionCoords]
);

const onResize = useCallback(() => {
const parent = getPositionNode(wrapper.current, positionNode);
if (parent && !getPositionNodeVisible(parent)) {
// Hide the menu if the item has become hidden. This might happen in
// a responsive table when columns become hidden as the page
// becomes smaller.
handleClose();
} else {
// Update the coordinates so that the menu stays relative to the
// toggle button.
updatePositionCoords();
}
}, [handleClose, positionNode, updatePositionCoords]);
const onScroll = useCallback(
(e) => {
const parent = getPositionNode(wrapper.current, positionNode);
// update position if the scroll event is triggered by the parent of the menu
if (parent && e.target.contains(parent)) {
// Update the coordinates so that the menu stays relative to the
// toggle button.
console.log("update position!");
updatePositionCoords();
}
},
[positionNode, updatePositionCoords]
);

useListener(window, onResize, "resize", true, isOpen);
useListener(window, onScroll, "scroll", false, isOpen, true);

return (
<span className={wrapperClass} ref={wrapperRef} {...wrapperProps}>
<span
className={contextualMenuClassName}
ref={wrapperRef}
{...wrapperProps}
>
{hasToggle ? (
<Button
appearance={toggleAppearance}
Expand All @@ -290,11 +310,11 @@ const ContextualMenu = <L,>({
className={classNames("p-contextual-menu__toggle", toggleClassName)}
disabled={toggleDisabled}
hasIcon={hasToggleIcon}
onClick={() => {
onClick={(evt: React.MouseEvent) => {
if (!isOpen) {
handleOpen();
openPortal(evt);
} else {
handleClose();
closePortal(evt);
}
}}
type="button"
Expand All @@ -317,23 +337,26 @@ const ContextualMenu = <L,>({
</Button>
) : null}
{isOpen && (
<ContextualMenuDropdown<L>
adjustedPosition={adjustedPosition}
autoAdjust={autoAdjust}
handleClose={handleClose}
constrainPanelWidth={constrainPanelWidth}
dropdownClassName={dropdownClassName}
dropdownContent={children}
id={id}
isOpen={isOpen}
links={links}
position={position}
positionCoords={positionCoords}
positionNode={getPositionNode(wrapper.current)}
scrollOverflow={scrollOverflow}
setAdjustedPosition={setAdjustedPosition}
{...dropdownProps}
/>
<Portal>
<ContextualMenuDropdown<L>
adjustedPosition={adjustedPosition}
autoAdjust={autoAdjust}
handleClose={closePortal}
constrainPanelWidth={constrainPanelWidth}
dropdownClassName={dropdownClassName}
dropdownContent={children}
id={id}
isOpen={isOpen}
links={links}
position={position}
positionCoords={positionCoords}
contextualMenuClassName={contextualMenuClassName}
positionNode={getPositionNode(wrapper.current)}
scrollOverflow={scrollOverflow}
setAdjustedPosition={setAdjustedPosition}
{...dropdownProps}
/>
</Portal>
)}
</span>
);
Expand Down
Loading

0 comments on commit f2f830c

Please sign in to comment.