mui / mui-x

MUI X: Build complex and data-rich applications using a growing list of advanced React components, like the Data Grid, Date and Time Pickers, Charts, and more!
https://mui.com/x/
4.13k stars 1.28k forks source link

The filter panel closes if you click in another modal window #10466

Open mimaxm opened 1 year ago

mimaxm commented 1 year ago

Order ID

72020

Duplicates

Latest version

The problem in depth πŸ”

We have a custom select in the filter panel. The select contains chips, when you hover over them a tooltip appears. There is a button in the tooltip that opens Drawer with a form. If I click inside the Drawer, the filter panel and select are closed. How can I prevent the filter panel and select from closing?

Here is a simple example in codesandbox: https://codesandbox.io/s/late-bash-f522xj

There is another bug here. The first time you click on the input in the Drawer, it loses focus. I found the workaround here. Is there another solution?

filter-panel.webm

Your environment 🌎

`npx @mui/envinfo` ``` System: OS: Linux 5.15 Ubuntu 20.04.6 LTS (Focal Fossa) Binaries: Node: 18.17.0 - ~/.nvm/versions/node/v18.17.0/bin/node Yarn: 3.6.3 - /usr/local/bin/yarn npm: 9.6.7 - ~/.nvm/versions/node/v18.17.0/bin/npm Browsers: Chrome: 117.0.5938.88 npmPackages: @emotion/react: 11.11.1 => 11.11.1 @emotion/styled: 11.11.0 => 11.11.0 @mui/base: 5.0.0-beta.15 @mui/core-downloads-tracker: 5.14.9 @mui/icons-material: 5.14.9 => 5.14.9 @mui/lab: 5.0.0-alpha.144 => 5.0.0-alpha.144 @mui/material: 5.14.9 => 5.14.9 @mui/private-theming: 5.14.9 @mui/styled-engine: 5.14.9 @mui/system: 5.14.9 => 5.14.9 @mui/types: 7.2.4 @mui/utils: 5.14.9 @mui/x-data-grid: 5.17.26 @mui/x-data-grid-premium: 5.17.26 => 5.17.26 @mui/x-data-grid-pro: 5.17.26 @mui/x-date-pickers: 5.0.20 => 5.0.20 @mui/x-license-pro: 5.17.12 @mui/x-tree-view: 6.0.0-alpha.1 @types/react: 18.2.21 => 18.2.21 react: 18.2.0 => 18.2.0 react-dom: 18.2.0 => 18.2.0 typescript: 5.2.2 => 5.2.2 ```
MBilalShafi commented 1 year ago

Hi @mimaxm, thank you for using MUI X and Data Grid.

It's an interesting use-case. I am curious about the UX choice you made here about opening a drawer from the filter panel dialog. The dialogs like filter panels are supposed to be made simple for the users and if they have too many multi-level nestings like opening drawers etc., it might get confusing for the users. If it has to be that complex, how about using an alternate UI like rendering a custom-made filter panel outside of the grid to have more control over things? A related recipe you might be interested in: https://mui.com/x/react-data-grid/filtering-recipes/#quck-filter-outside-of-the-grid I'll be glad to hear your thoughts on this.

Why filter panel closes on Drawer click? Because that's the normal way the filter panel closes, i.e. when a clickAway event fires. If we change that behavior, how do you suggest the user could close the filter panel?

mimaxm commented 1 year ago

Thanks for the answer. This logic is needed to be able to edit entities that are a set of multiple fields. These entities are in another table, in another section. You can edit them there. But it is convenient to have access to editing them from anywhere in the interface where they are used. If we had the ability to disable clickAwayListener for the filter panel based on some condition, then we could disable clickAwayListener if Drawer is open.

Rendering a custom filter panel outside of the grid is not an option for us at the moment.

MBilalShafi commented 1 year ago

Ah ok, I think it should be achievable by having GridPanel accept an override for ClickAwayListenerProps.

diff --git a/packages/grid/x-data-grid/src/components/panel/GridPanel.tsx b/packages/grid/x-data-grid/src/components/panel/GridPanel.tsx
index 175de65aa..d794fd665 100644
--- a/packages/grid/x-data-grid/src/components/panel/GridPanel.tsx
+++ b/packages/grid/x-data-grid/src/components/panel/GridPanel.tsx
@@ -3,7 +3,9 @@ import PropTypes from 'prop-types';
 import clsx from 'clsx';
 import { styled } from '@mui/material/styles';
 import { unstable_generateUtilityClasses as generateUtilityClasses } from '@mui/utils';
-import ClickAwayListener from '@mui/material/ClickAwayListener';
+import ClickAwayListener, {
+  ClickAwayListenerProps as ClickAwayListenerPropsType,
+} from '@mui/material/ClickAwayListener';
 import Paper from '@mui/material/Paper';
 import Popper from '@mui/material/Popper';
 import { useGridApiContext } from '../../hooks/utils/useGridApiContext';
@@ -28,6 +30,7 @@ export interface GridPanelProps extends Partial<React.ComponentProps<typeof Grid
    */
   classes?: Partial<GridPanelClasses>;
   open: boolean;
+  ClickAwayListenerProps?: Partial<ClickAwayListenerPropsType>;
 }

 export const gridPanelClasses = generateUtilityClasses<keyof GridPanelClasses>('MuiDataGrid', [
@@ -55,7 +58,7 @@ const GridPaperRoot = styled(Paper, {
 }));

 const GridPanel = React.forwardRef<HTMLDivElement, GridPanelProps>((props, ref) => {
-  const { children, className, classes: classesProp, ...other } = props;
+  const { children, className, classes: classesProp, ClickAwayListenerProps, ...other } = props;
   const apiRef = useGridApiContext();
   const rootProps = useGridRootProps();
   const classes = gridPanelClasses;
@@ -121,7 +124,11 @@ const GridPanel = React.forwardRef<HTMLDivElement, GridPanelProps>((props, ref)
       modifiers={modifiers}
       {...other}
     >
-      <ClickAwayListener mouseEvent="onMouseUp" onClickAway={handleClickAway}>
+      <ClickAwayListener
+        mouseEvent="onMouseUp"
+        onClickAway={handleClickAway}
+        {...ClickAwayListenerProps}
+      >
         <GridPaperRoot
           className={classes.paper}
           ownerState={rootProps}

And the users could use this as:

const ClickAwayListenerProps = drawerOpen ? { onClickAway: () => {} } : {};
<DataGrid
  {...otherProps}
  slotProps={{
    panel: {
      ClickAwayListenerProps
    }
  }}
/> 

I am not sure about this solution though.

Another anti-pattern option could be to make clickAwayListener part of slotProps, I won't do it as we don't do it for external components which are not slots, but we can probably think to make it a slot too, I guess it'll also be a part of Joy UI integration (isolating the X repo with core aspect), right @cherniavskii?

@mui/xgrid Your opinions are appreciated!

mimaxm commented 1 year ago

@MBilalShafi I like this solution. I think we can use it.

MBilalShafi commented 1 year ago

Great @mimaxm, feel free to open up a PR with the change if you want.