1
0
mirror of https://github.com/lensapp/lens.git synced 2025-05-20 05:10:56 +00:00

Menu: extended kinds of positions when rendered inside parent's element (usePortal=false)

Signed-off-by: Roman <ixrock@gmail.com>
This commit is contained in:
Roman 2021-04-06 15:03:21 +03:00
parent 33c405bdcf
commit 4e459fdff6
4 changed files with 58 additions and 21 deletions

View File

@ -32,7 +32,6 @@
margin-bottom: $margin;
.Icon {
margin-bottom: $margin * 1.5;
border-radius: $radius;
padding: $padding / 3;
color: var(--textColorPrimary);

View File

@ -118,13 +118,13 @@ export class ClustersMenu extends React.Component<Props> {
<div className="WorkspaceMenu">
<Icon big material="menu" id="workspace-menu-icon" data-test-id="workspace-menu" />
<Menu
usePortal
htmlFor="workspace-menu-icon"
className="WorkspaceMenu"
isOpen={this.workspaceMenuVisible}
open={() => this.workspaceMenuVisible = true}
close={() => this.workspaceMenuVisible = false}
toggleEvent="click"
position={{right: "outside", top: "inside"}}
>
<MenuItem onClick={() => navigate(addClusterURL())} data-test-id="add-cluster-menu-item">
<Icon small material="add" /> Add Cluster

View File

@ -9,6 +9,8 @@
border: 1px solid $borderColor;
z-index: 101;
// TODO: support predefined positions setup when rendered in document.body
// auto-positioning currently applied inside component on menu open
&.portal {
left: -1000px;
top: -1000px;
@ -22,23 +24,46 @@
}
}
// predefined positions without `usePortal` (default) where menu is rendered inside it's parent dom tree.
&:not(.portal) {
margin: $margin 0;
&.left {
left: 0;
&-inside {
left: 0;
}
&-outside {
right: 100%;
}
}
&.right {
right: 0;
&-inside {
right: 0;
}
&-outside {
left: 100%;
}
}
&.top {
bottom: 100%;
&-inside {
top: 0;
}
&-outside {
bottom: 100%;
}
}
&.bottom {
top: 100%;
&-inside {
bottom: 0;
}
&-outside {
top: 100%;
}
}
}

View File

@ -9,12 +9,13 @@ import debounce from "lodash/debounce";
export const MenuContext = React.createContext<MenuContextValue>(null);
export type MenuContextValue = Menu;
export type MenuPositionSide = "inside" | "outside";
export interface MenuPosition {
left?: boolean;
top?: boolean;
right?: boolean;
bottom?: boolean;
left?: MenuPositionSide;
top?: MenuPositionSide;
right?: MenuPositionSide;
bottom?: MenuPositionSide;
}
export interface MenuProps {
@ -35,11 +36,16 @@ export interface MenuProps {
}
interface State {
position?: MenuPosition;
position?: {
left?: boolean;
top?: boolean;
right?: boolean;
bottom?: boolean;
};
}
const defaultPropsMenu: Partial<MenuProps> = {
position: { right: true, bottom: true },
position: { left: "inside", bottom: "outside" },
autoFocus: false,
usePortal: false,
closeOnClickItem: true,
@ -137,7 +143,12 @@ export class Menu extends React.Component<MenuProps, State> {
}
// setup initial position
const position: MenuPosition = { left: true, bottom: true };
const position = {
bottom: true,
left: true,
right: false,
top: false,
};
this.elem.style.left = `${left}px`;
this.elem.style.top = `${bottom}px`;
@ -248,12 +259,14 @@ export class Menu extends React.Component<MenuProps, State> {
}
render() {
const { position, id } = this.props;
let { className, usePortal } = this.props;
const { position = {}, id, className } = this.props;
let { usePortal } = this.props;
className = cssNames("Menu", className, this.state.position || position, {
portal: usePortal,
});
const positionClasses = usePortal
? this.state.position // auto-corrected position to be visible in viewport
: Object.entries(position).map(entry => entry.join("-")); // positioning relative to parent
const classNames = cssNames("Menu", className, { portal: usePortal }, positionClasses);
let children = this.props.children as ReactElement<any>;
@ -273,7 +286,7 @@ export class Menu extends React.Component<MenuProps, State> {
const menu = (
<MenuContext.Provider value={this}>
<Animate enter={this.isOpen}>
<ul id={id} className={className} ref={this.bindRef}>
<ul id={id} className={classNames} ref={this.bindRef}>
{menuItems}
</ul>
</Animate>