Skip to content

Commit ba100cc

Browse files
youlunajinliang.wjl
andauthored
feat(Overlay): support render overlay in shadow dom (#1869)
Co-authored-by: jinliang.wjl <jinliang.wjl@alibaba-inc.com>
1 parent d55c82d commit ba100cc

File tree

2 files changed

+69
-0
lines changed

2 files changed

+69
-0
lines changed

src/overlay/overlay.jsx

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -633,6 +633,45 @@ class Overlay extends Component {
633633
}
634634
}
635635

636+
isInShadowDOM(node) {
637+
return node.getRootNode ? node.getRootNode().nodeType === 11 : false;
638+
}
639+
640+
getEventPath(event) {
641+
// 参考 https://github.com/spring-media/react-shadow-dom-retarget-events/blob/master/index.js#L29
642+
return (
643+
event.path ||
644+
(event.composedPath && event.composedPath()) ||
645+
this.composedPath(event.target)
646+
);
647+
}
648+
649+
composedPath(el) {
650+
const path = [];
651+
while (el) {
652+
path.push(el);
653+
if (el.tagName === 'HTML') {
654+
path.push(document);
655+
path.push(window);
656+
return path;
657+
}
658+
el = el.parentElement;
659+
}
660+
}
661+
662+
matchInShadowDOM(node, e) {
663+
if (this.isInShadowDOM(node)) {
664+
// Shadow DOM 环境中,触发点击事件,监听 document click 事件获得的事件源
665+
// 并非实际触发的 dom 节点,而是 Shadow DOM 的 host 节点
666+
// 进而会导致如 Select 组件的下拉弹层打开后立即关闭等问题
667+
// 因此额外增加 node 和 eventPath 的判断
668+
const eventPath = this.getEventPath(e);
669+
return node === eventPath[0] || node.contains(eventPath[0]);
670+
}
671+
672+
return false;
673+
}
674+
636675
handleDocumentClick(e) {
637676
if (this.state.visible) {
638677
const { safeNode } = this.props;
@@ -649,6 +688,7 @@ class Overlay extends Component {
649688
node &&
650689
(node === e.target ||
651690
node.contains(e.target) ||
691+
this.matchInShadowDOM(node, e) ||
652692
(e.target !== document &&
653693
!document.documentElement.contains(e.target)))
654694
) {

test/overlay/index-spec.js

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -787,6 +787,35 @@ describe('Popup', () => {
787787
});
788788
});
789789

790+
it('should support render in shadow dom', () => {
791+
return co(function*() {
792+
const host = document.createElement('div');
793+
const shadowRoot = host.attachShadow({ mode: 'open' });
794+
document.body.appendChild(host);
795+
796+
ReactDOM.render((
797+
<Popup trigger={<button>Open</button>} triggerType="click">
798+
<span className="content">Hello World From Popup!</span>
799+
</Popup>
800+
), shadowRoot);
801+
802+
yield delay(300);
803+
const btn = shadowRoot.querySelector('button');
804+
// NOTE: 此处不能使用 ReactTestUtils.Simulate.click(btn);
805+
btn.click();
806+
807+
yield delay(300);
808+
assert(document.querySelector('.next-overlay-wrapper'));
809+
810+
btn.click();
811+
yield delay(300);
812+
assert(!document.querySelector('.next-overlay-wrapper'));
813+
814+
ReactDOM.unmountComponentAtNode(shadowRoot);
815+
document.body.removeChild(host);
816+
});
817+
});
818+
790819
// https://riddle.alibaba-inc.com/riddles/b58b48a6
791820
it('should support container return a react component', () => {
792821
class App extends React.Component {

0 commit comments

Comments
 (0)