Skip to content

Commit

Permalink
fix(Overlay): overflow bug with mulitple overlay
Browse files Browse the repository at this point in the history
  • Loading branch information
皆虚 authored and youluna committed Jun 21, 2021
1 parent d1a4990 commit ffa20f3
Show file tree
Hide file tree
Showing 2 changed files with 111 additions and 62 deletions.
63 changes: 39 additions & 24 deletions src/overlay/overlay.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,12 @@ const getStyleProperty = (node, name) => {
return ret;
};

const modals = [];
let bodyOverflow, bodyPaddingRight;
// 存 containerNode 信息
const containerNodeList = [];

/**
* Overlay
* */
*/
class Overlay extends Component {
static propTypes = {
prefix: PropTypes.string,
Expand Down Expand Up @@ -508,46 +508,61 @@ class Overlay extends Component {

beforeOpen() {
if (this.props.disableScroll) {
if (modals.length === 0) {
const containerNode = getContainerNode(this.props) || document.body;
const cnInfo = containerNodeList.find(m => m.containerNode === containerNode) || {
containerNode,
count: 0,
};

if (cnInfo.count === 0) {
const { overflow, paddingRight } = containerNode.style;
const style = {
overflow: 'hidden',
};

this.containerNode = getContainerNode(this.props) || document.body;
bodyOverflow = this.containerNode.style.overflow;
cnInfo.overflow = overflow;

if (hasScroll(this.containerNode)) {
bodyPaddingRight = this.containerNode.style.paddingRight;
style.paddingRight = `${dom.getStyle(this.containerNode, 'paddingRight') +
dom.scrollbar().width}px`;
if (hasScroll(containerNode)) {
cnInfo.paddingRight = paddingRight;
style.paddingRight = `${dom.getStyle(containerNode, 'paddingRight') + dom.scrollbar().width}px`;
}

dom.setStyle(this.containerNode, style);
dom.setStyle(containerNode, style);
containerNodeList.push(cnInfo);
}
modals.push(this);

cnInfo.count++;
this._containerNode = containerNode;
}
}

beforeClose() {
if (this.props.disableScroll) {
const index = modals.indexOf(this);
if (index > -1) {
if (modals.length === 1) {
const idx = containerNodeList.findIndex(cn => cn.containerNode === this._containerNode);

if (idx !== -1) {
const cnInfo = containerNodeList[idx];
const { overflow, paddingRight } = cnInfo;

// 最后一个 overlay 的时候再将样式重置回去
if (cnInfo.count === 1 && this._containerNode) {
const style = {
overflow: bodyOverflow,
overflow,
};
if (bodyPaddingRight !== undefined) {
style.paddingRight = bodyPaddingRight;
}

this.containerNode && dom.setStyle(this.containerNode, style);
if (paddingRight !== undefined) {
style.paddingRight = paddingRight;
}

bodyOverflow = undefined;
bodyPaddingRight = undefined;
this.containerNode = undefined;
dom.setStyle(this._containerNode, style);
this._containerNode = undefined;
}

modals.splice(index, 1);
cnInfo.count--;

if (cnInfo.count === 0) {
containerNodeList.splice(idx, 1);
}
}
}
}
Expand Down
110 changes: 72 additions & 38 deletions test/overlay/index-spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import Overlay from '../../src/overlay/index';
import Dialog from '../../src/dialog/index';
import Balloon from '../../src/balloon/index';
import Button from '../../src/button/index';
import Drawer from '../../src/drawer/index';
import ConfigProvider from '../../src/config-provider/index';
import '../../src/button/style.js';
import '../../src/overlay/style.js';
Expand Down Expand Up @@ -637,6 +638,67 @@ describe('Overlay', () => {

assert(document.querySelector('.overlay-btn').style.left === '73.5px');
});

it('should set overflow hidden to container', () => {
function Demo() {
const [visible, setVisible] = useState(false);

return (
<div id="luodan">
<button className="btn" onClick={() => setVisible(true)}>
Open dialog
</button>
<Dialog visible={visible} popupContainer="luodan">
Small Content in a fixed size Dialog
</Dialog>
</div>
);
}

wrapper = render(<Demo />);
wrapper.find('.btn')[0].click();

const container = wrapper.find('#luodan')[0];

assert(container.style.overflow === 'hidden');
assert(container.style.paddingRight === '');

wrapper.find('.btn')[0].click();
});

// https://github.com/alibaba-fusion/next/issues/3104
it('fix overflow bug with multiple overlay', () => {
function MyDrawer() {
const [visible, setVisible] = useState(false);
const onOpen = () => {
setVisible(true);
};

const onClose = () => {
Dialog.confirm({
content: '确认关闭',
});
};

return (
<div>
<Button className="btn-open" onClick={onOpen} />
<Button className="btn-close" onClick={() => setVisible(false)} />
<Drawer visible={visible} onClose={onClose} />
</div>
);
}

wrapper = render(<MyDrawer />);
simulateEvent.simulate(document.querySelector('.btn-open'), 'click');
assert(document.body.style.overflow === 'hidden');
simulateEvent.simulate(document.querySelector('.next-overlay-backdrop'), 'click');
simulateEvent.simulate(document.querySelector('.btn-close '), 'click');
assert(document.body.style.overflow === 'hidden');
simulateEvent.simulate(document.querySelector('.next-dialog-btn'), 'click');
document.body.style.overflow = undefined;
assert(document.body.style.overflow === '');
});
});

describe('Popup', () => {
Expand Down Expand Up @@ -946,50 +1008,22 @@ describe('Popup', () => {
assert(overlayInner.style.top !== '0px');
});

it('should set overflow hidden to container', () => {
function Demo() {
const [visible, setVisible] = useState(false);

return (
<div id="luodan">
<button className="btn" onClick={() => setVisible(true)}>
Open dialog
</button>
<Dialog visible={visible} popupContainer="luodan">
Small Content in a fixed size Dialog
</Dialog>
</div>
);
}

wrapper = render(<Demo />);
wrapper.find('.btn')[0].click();

const container = wrapper.find('#luodan')[0];

assert(container.style.overflow === 'hidden');
assert(container.style.paddingRight === '');

wrapper.find('.btn')[0].click();
ReactDOM.unmountComponentAtNode(container);
});

it('should configprovider work', () => {
const container = document.createElement('div');

function Demo() {
return (
<ConfigProvider popupContainer={() => document.getElementById('config-provider')}>
<div>
<div id="config-provider"/>
<div id="self"/>
<Popup visible>
<span id="test-popup">this is popup</span>
</Popup>
<Balloon visible popupContainer={() => document.getElementById('self')}>
<span id="test-balloon">this is balloon</span>
</Balloon>
</div>
<div>
<div id="config-provider" />
<div id="self" />
<Popup visible>
<span id="test-popup">this is popup</span>
</Popup>
<Balloon visible popupContainer={() => document.getElementById('self')}>
<span id="test-balloon">this is balloon</span>
</Balloon>
</div>
</ConfigProvider>
);
}
Expand Down

0 comments on commit ffa20f3

Please sign in to comment.