Merge pull request #4341 from appsmithorg/fix/dropdown-overlap-modal

fix: Dropdown option gets overlapped on the ModalComponent
This commit is contained in:
Somangshu Goswami 2021-06-22 15:37:44 +05:30 committed by GitHub
commit 3c8944cc1c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 92 additions and 34 deletions

View File

@ -4,6 +4,7 @@ import Select from "react-select";
import { WrappedFieldInputProps } from "redux-form";
import { theme } from "constants/DefaultTheme";
import { SelectComponentsConfig } from "react-select/src/components";
import { LayersContext } from "../../../constants/Layers";
export type DropdownProps = {
options: Array<{
@ -55,11 +56,16 @@ const selectStyles = {
};
export function BaseDropdown(props: DropdownProps) {
const layer = React.useContext(LayersContext);
const { customSelectStyles, input } = props;
const menuPortalStyle = {
menuPortal: (styles: any) => ({ ...styles, zIndex: layer.max }),
};
return (
<Select
menuPortalTarget={document.body}
styles={{ ...selectStyles, ...customSelectStyles }}
styles={{ ...selectStyles, ...customSelectStyles, ...menuPortalStyle }}
{...input}
isDisabled={props.isDisabled}
isSearchable={props.isSearchable}

View File

@ -229,17 +229,35 @@ const StyledMultiDropDown = styled(MultiDropDown)<{
}
}
`;
interface DropDownComponentState {
portalContainer: HTMLElement;
}
class DropDownComponent extends React.Component<
DropDownComponentProps,
DropDownComponentState
> {
private _menu = React.createRef<HTMLDivElement>();
constructor(props: DropDownComponentProps) {
super(props);
this.state = { portalContainer: this._menu.current as HTMLElement };
}
componentDidMount() {
this.setState({
portalContainer: this.props.getDropdownPosition(this._menu.current),
});
}
class DropDownComponent extends React.Component<DropDownComponentProps> {
render() {
const { options, selectedIndexArr } = this.props;
const { portalContainer } = this.state;
const selectedItems = selectedIndexArr
? _.map(selectedIndexArr, (index) => options[index])
: [];
const hideCloseButtonIndex = -1;
return (
<DropdownContainer>
<DropdownContainer ref={this._menu as React.RefObject<HTMLDivElement>}>
<DropdownStyles />
<StyledControlGroup
fill
@ -300,6 +318,7 @@ class DropDownComponent extends React.Component<DropDownComponentProps> {
popoverProps={{
minimal: true,
usePortal: true,
portalContainer,
modifiers: {
preventOverflow: {
enabled: false,
@ -426,6 +445,7 @@ export interface DropDownComponentProps extends ComponentProps {
isFilterable: boolean;
width: number;
height: number;
getDropdownPosition: (node: HTMLDivElement | null) => HTMLElement;
}
export default DropDownComponent;

View File

@ -92,39 +92,50 @@ export function ModalComponent(props: ModalComponentProps) {
}
}, [props.scrollContents]);
return (
<Container
bottom={props.bottom}
height={props.height}
left={props.left}
right={props.bottom}
top={props.top}
width={props.width}
zIndex={props.zIndex !== undefined ? props.zIndex : Layers.modalWidget}
<Overlay
canEscapeKeyClose={false}
canOutsideClickClose={false}
enforceFocus={false}
hasBackdrop={false}
isOpen={props.isOpen}
onClose={props.onClose}
portalClassName="bp3-modal-widget"
usePortal
>
<Overlay
canEscapeKeyClose={props.canEscapeKeyClose}
canOutsideClickClose={props.canOutsideClickClose}
className={props.overlayClassName}
enforceFocus={false}
hasBackdrop={
props.hasBackDrop !== undefined ? !!props.hasBackDrop : true
}
isOpen={props.isOpen}
onClose={props.onClose}
usePortal={false}
<Container
bottom={props.bottom}
height={props.height}
left={props.left}
right={props.bottom}
top={props.top}
width={props.width}
zIndex={props.zIndex !== undefined ? props.zIndex : Layers.modalWidget}
>
<div>
<Content
className={`${getCanvasClassName()} ${props.className}`}
height={props.height}
ref={modalContentRef}
scroll={props.scrollContents}
>
{props.children}
</Content>
</div>
</Overlay>
</Container>
<Overlay
canEscapeKeyClose={props.canEscapeKeyClose}
canOutsideClickClose={props.canOutsideClickClose}
className={props.overlayClassName}
enforceFocus={false}
hasBackdrop={
props.hasBackDrop !== undefined ? !!props.hasBackDrop : true
}
isOpen={props.isOpen}
onClose={props.onClose}
usePortal={false}
>
<div>
<Content
className={`${getCanvasClassName()} ${props.className}`}
height={props.height}
ref={modalContentRef}
scroll={props.scrollContents}
>
{props.children}
</Content>
</div>
</Overlay>
</Container>
</Overlay>
);
}

View File

@ -11,6 +11,7 @@ export enum Indices {
Layer7,
Layer8,
Layer9,
Layer21 = 21,
LayerMax = 99999,
}
@ -22,6 +23,10 @@ export const Layers = {
positionedWidget: Indices.Layer1,
// Modal needs to higher than other widgets.
modalWidget: Indices.Layer2,
// Dropdown portaled to the canvas
dropdownWidget: Indices.Layer2,
// dropdown portaled to Modal Container with higher index than Overlay
dropdownModalWidget: Indices.Layer21,
selectedWidget: Indices.Layer2,
// Layers when dragging
animatedSnappingDropZone: Indices.Layer2,

View File

@ -93,3 +93,12 @@ div.bp3-popover-arrow {
background: white !important;
border-bottom: 1px solid #E7E7E7 !important;
}
/* making both the Modal layer and the Dropdown layer */
.bp3-modal-widget, .appsmith_widget_0 > .bp3-portal {
z-index: 2 !important;
}
/* Portals on the Modal widget */
.bp3-modal-widget .bp3-portal {
z-index: 21 !important;
}

View File

@ -150,6 +150,12 @@ class DropdownWidget extends BaseWidget<DropdownWidgetProps, WidgetState> {
? this.props.selectedOptionValueArr
: [];
}
getDropdownPosition = (node: HTMLDivElement | null) => {
if (Boolean(node?.closest(".bp3-modal-widget"))) {
return document.querySelector(".bp3-modal-widget") as HTMLElement;
}
return document.querySelector(".appsmith_widget_0") as HTMLElement;
};
getPageView() {
const options = _.isArray(this.props.options) ? this.props.options : [];
@ -161,6 +167,7 @@ class DropdownWidget extends BaseWidget<DropdownWidgetProps, WidgetState> {
return (
<DropDownComponent
disabled={this.props.isDisabled}
getDropdownPosition={this.getDropdownPosition}
height={componentHeight}
isFilterable={this.props.isFilterable}
isLoading={this.props.isLoading}