mui / material-ui

Material UI: Comprehensive React component library that implements Google's Material Design. Free forever.
https://mui.com/material-ui/
MIT License
93.74k stars 32.24k forks source link

[Dialog] Add Divider to Dialog #3155

Closed SPAHI4 closed 5 years ago

SPAHI4 commented 8 years ago

Divider added to the content of Dialog scrolls with content. Divider added as action has padding. Would be great to have something like this

m2mathew commented 8 years ago

We are using the MUI <Divider /> component inside our dialogs to realize the Material Design specs for scrolling dialog content.

@SPAHI4 Are you wanting a prop that you pass in that automatically adds the divider if the content is scrollable? Also, should we mirror the spec to include the divider at the top and bottom of the content like in my .gif?

eps1lon commented 5 years ago

See #14735 for a possible solution that is already achievable. We're somewhat open to review a solution that only requires using a prop. However it's unlikely that we'll accept a dynamic solution that has built-in overflow detection unless it has a small bundle footprint. The current solution with using Divider doesn't bloat the bundle of everyone and is IMO preferred. If we want to increase the size for everyone it should be very small.

WordlessEcho commented 3 years ago

Is it possible to hide top divider while scrolling to the top, hide bottom divider while scrolling to the end?

WordlessEcho commented 3 years ago

Is it possible to hide top divider while scrolling to the top, hide bottom divider while scrolling to the end?

So I make it by myself.

Here is an example on CodeSandbox.

Example

dialog-example

Details

Create two variables to control dividers.

const [topDivider, setTopDivider] = useState(false);
const [bottomDivider, setBottomDivider] = useState(false);

Create a function to initilize status of dividers. Because Dialog have its own "lifecycle". (You will see the explanation below)

const initializeDividers = () => {
  setTopDivider(false);
  setBottomDivider(false);

  /* ... */
};

Detect if scrollbar exist by comparing scrollHeightwith clientHeight. [1] (The id in getElementById is for DialogContent)

const initializeDividers = () => {
  /* ... */

  const dialogContent = document.getElementById('dialog-content');

  if (dialogContent !== null) {
    if (dialogContent.scrollHeight > dialogContent.clientHeight) {
      setBottomDivider(true);
    }
  }
};

Adding initializeDividers to Dialog in onEnter. Because display of Dialog is control by open. (Now you know why we don't use Effect Hook) You will get null if you are using React Effect Hook to get element.

<Dialog
  open={/* variable from caller */}
  onEnter={initializeDividers}
  scroll="paper"
>

{/* ... */}

Add Dividers before & after DialogContent with its variable from State Hook. And don't forget to set a id for DialogContent.

{topDivider ? <Divider /> : null}
<DialogContent id="dialog-content">
  {/* ... */}
</DialogContent>
{bottomDivider ? <Divider /> : null}

Now let's handle the scrolling.

You need to listen the onScroll event in DialogContent.

const handleScrolling = (e: React.UIEvent<HTMLDivElement>) => {
  /* ... */
};

/* ... */

<DialogContent id="dialog-content" onScroll={handleScrolling}>
  {/* ... */}
</DialogContent>

Assert the type of event.target to HTMLDivElement. [2]

const handleScrolling = (e: React.UIEvent<HTMLDivElement>) => {
  if (e === undefined) {
    return;
  }

  const { scrollTop, scrollHeight, offsetHeight } = e.currentTarget;

  /* ... */
};

Compare the scrollTop with the difference between scrollHeight and scrollHeight. [3] [4]

const handleScrolling = (e: React.UIEvent<HTMLDivElement>) => {
  /* ... */

  setTopDivider(scrollTop !== 0);
  setBottomDivider(
    scrollTop !== scrollHeight - offsetHeight
  );
};

Updates

Credits & References

Thanks all of them.

[1]: Check whether HTML element has scrollbars using JavaScript - GeeksforGeeks [2]: reactjs - How to describe type scroll events? - Stack Overflow [3]: reactjs - is this possible to get scroll position in material-ui select list on Scroll? - Stack Overflow [4]: browser - How to get scrollbar position with Javascript? - Stack Overflow