Repository: mui/material-ui (TypeScript)
Date: 2019-10-08 01:35:39+00:00
Task type: Bug Fix

Issue:
[Popper] Render function `placement` argument is not updated
class MuiTooltip-tooltipPlacementBottom  is always applied by  default.
if props placement  is set to top then MuiTooltip-tooltipPlacementTop is always applied.
It's  not upated according  to x-placement anymore



Issue discussion:

Solution patch:
diff --git a/packages/material-ui/src/Popper/Popper.js b/packages/material-ui/src/Popper/Popper.js
--- a/packages/material-ui/src/Popper/Popper.js
+++ b/packages/material-ui/src/Popper/Popper.js
@@ -78,14 +78,9 @@ const Popper = React.forwardRef(function Popper(props, ref) {
    * modifiers.flip is essentially a flip for controlled/uncontrolled behavior
    */
   const [placement, setPlacement] = React.useState(rtlPlacement);
-  if (rtlPlacement !== placement) {
-    setPlacement(rtlPlacement);
-  }
 
   const handleOpen = React.useCallback(() => {
-    const popperNode = tooltipRef.current;
-
-    if (!popperNode || !anchorEl || !open) {
+    if (!tooltipRef.current || !anchorEl || !open) {
       return;
     }
 
@@ -124,7 +119,7 @@ const Popper = React.forwardRef(function Popper(props, ref) {
       }
     }
 
-    const popper = new PopperJS(getAnchorEl(anchorEl), popperNode, {
+    const popper = new PopperJS(getAnchorEl(anchorEl), tooltipRef.current, {
       placement: rtlPlacement,
       ...popperOptions,
       modifiers: {
@@ -141,6 +136,7 @@ const Popper = React.forwardRef(function Popper(props, ref) {
       },
       // We could have been using a custom modifier like react-popper is doing.
       // But it seems this is the best public API for this use case.
+      onCreate: createChainedFunction(handlePopperUpdate, popperOptions.onCreate),
       onUpdate: createChainedFunction(handlePopperUpdate, popperOptions.onUpdate),
     });
     handlePopperRefRef.current(popper);


Test patch:
diff --git a/packages/material-ui/src/Popper/Popper.test.js b/packages/material-ui/src/Popper/Popper.test.js
--- a/packages/material-ui/src/Popper/Popper.test.js
+++ b/packages/material-ui/src/Popper/Popper.test.js
@@ -1,9 +1,10 @@
 import React from 'react';
-import { assert } from 'chai';
+import { assert, expect } from 'chai';
 import { spy, useFakeTimers } from 'sinon';
 import PropTypes from 'prop-types';
 import { createMount } from '@material-ui/core/test-utils';
 import describeConformance from '@material-ui/core/test-utils/describeConformance';
+import { cleanup, createClientRender } from 'test/utils/createClientRender';
 import consoleErrorMock from 'test/utils/consoleErrorMock';
 import PopperJS from 'popper.js';
 import Grow from '../Grow';
@@ -11,6 +12,7 @@ import Popper from './Popper';
 
 describe('<Popper />', () => {
   let mount;
+  const render = createClientRender({ strict: true });
   const defaultProps = {
     anchorEl: () => window.document.createElement('svg'),
     children: <span>Hello World</span>,
@@ -21,6 +23,10 @@ describe('<Popper />', () => {
     mount = createMount({ strict: true });
   });
 
+  afterEach(() => {
+    cleanup();
+  });
+
   after(() => {
     mount.cleanUp();
   });
@@ -96,6 +102,24 @@ describe('<Popper />', () => {
         assert.strictEqual(renderSpy.args[0][0], test.out);
       });
     });
+
+    it('should flip placement when edge is reached', () => {
+      const renderSpy = spy();
+      const popperRef = React.createRef();
+      render(
+        <Popper popperRef={popperRef} {...defaultProps} placement="bottom">
+          {({ placement }) => {
+            renderSpy(placement);
+            return null;
+          }}
+        </Popper>,
+      );
+      expect(renderSpy.args).to.deep.equal([['bottom'], ['bottom']]);
+      popperRef.current.options.onUpdate({
+        placement: 'top',
+      });
+      expect(renderSpy.args).to.deep.equal([['bottom'], ['bottom'], ['top'], ['top']]);
+    });
   });
 
   describe('prop: open', () => {