diff --git a/docs/demo/portal.md b/docs/demo/portal.md
deleted file mode 100644
index 6ecd6369..00000000
--- a/docs/demo/portal.md
+++ /dev/null
@@ -1,8 +0,0 @@
----
-title: portal
-nav:
- title: Demo
- path: /demo
----
-
-
diff --git a/docs/examples/portal.tsx b/docs/examples/portal.tsx
deleted file mode 100644
index 50b30c3a..00000000
--- a/docs/examples/portal.tsx
+++ /dev/null
@@ -1,26 +0,0 @@
-import React from 'react';
-import PortalWrapper from 'rc-util/es/PortalWrapper';
-
-const Demo: React.FC = () => {
- const divRef = React.useRef(null);
- const outerRef = React.useRef(null);
-
- React.useEffect(() => {
- console.log('>>>', divRef.current);
- }, []);
-
- function getRef() {
- return outerRef.current;
- }
-
- return (
- <>
-
- {() => 2333
}
-
-
- >
- );
-};
-
-export default Demo;
diff --git a/src/Portal.tsx b/src/Portal.tsx
index 1e0b4c88..a743aee8 100644
--- a/src/Portal.tsx
+++ b/src/Portal.tsx
@@ -45,8 +45,7 @@ const Portal = forwardRef((props, ref) => {
parentRef.current.appendChild(containerRef.current);
}
return () => {
- // [Legacy] This should not be handle by Portal but parent PortalWrapper instead.
- // Since some component use `Portal` directly, we have to keep the logic here.
+ // [Legacy] Some components use `Portal` directly, we have to keep the logic here.
containerRef.current?.parentNode?.removeChild(containerRef.current);
};
}, []);
diff --git a/src/PortalWrapper.tsx b/src/PortalWrapper.tsx
deleted file mode 100644
index a5fa3555..00000000
--- a/src/PortalWrapper.tsx
+++ /dev/null
@@ -1,242 +0,0 @@
-/* eslint-disable no-underscore-dangle,react/require-default-props */
-import * as React from 'react';
-import raf from './raf';
-import Portal from './Portal';
-import type { PortalRef } from './Portal';
-import canUseDom from './Dom/canUseDom';
-import setStyle from './setStyle';
-import ScrollLocker from './Dom/scrollLocker';
-
-let openCount = 0;
-const supportDom = canUseDom();
-
-/** @private Test usage only */
-export function getOpenCount() {
- return process.env.NODE_ENV === 'test' ? openCount : 0;
-}
-
-// https://github.com/ant-design/ant-design/issues/19340
-// https://github.com/ant-design/ant-design/issues/19332
-let cacheOverflow: React.CSSProperties = {};
-
-const getParent = (getContainer: GetContainer) => {
- if (!supportDom) {
- return null;
- }
- if (getContainer) {
- if (typeof getContainer === 'string') {
- return document.querySelectorAll(getContainer)[0];
- }
- if (typeof getContainer === 'function') {
- return getContainer();
- }
- if (
- typeof getContainer === 'object' &&
- getContainer instanceof window.HTMLElement
- ) {
- return getContainer;
- }
- }
- return document.body;
-};
-
-export type GetContainer = string | HTMLElement | (() => HTMLElement);
-
-export interface PortalWrapperProps {
- visible?: boolean;
- getContainer?: GetContainer;
- wrapperClassName?: string;
- forceRender?: boolean;
- children: (info: {
- getOpenCount: () => number;
- getContainer: () => HTMLElement;
- switchScrollingEffect: () => void;
- scrollLocker: ScrollLocker;
- ref?: (c: any) => void;
- }) => React.ReactNode;
-}
-
-class PortalWrapper extends React.Component {
- container?: HTMLElement;
-
- componentRef = React.createRef();
-
- rafId?: number;
-
- scrollLocker: ScrollLocker;
-
- constructor(props: PortalWrapperProps) {
- super(props);
- this.scrollLocker = new ScrollLocker({
- container: getParent(props.getContainer) as HTMLElement,
- });
- }
-
- renderComponent?: (info: {
- afterClose: (...params: any[]) => void;
- onClose: (...params: any[]) => void;
- visible: boolean;
- }) => void;
-
- componentDidMount() {
- this.updateOpenCount();
-
- if (!this.attachToParent()) {
- this.rafId = raf(() => {
- this.forceUpdate();
- });
- }
- }
-
- componentDidUpdate(prevProps: PortalWrapperProps) {
- this.updateOpenCount(prevProps);
- this.updateScrollLocker(prevProps);
-
- this.setWrapperClassName();
- this.attachToParent();
- }
-
- updateScrollLocker = (prevProps?: Partial) => {
- const { visible: prevVisible } = prevProps || {};
- const { getContainer, visible } = this.props;
-
- if (
- visible &&
- visible !== prevVisible &&
- supportDom &&
- getParent(getContainer) !== this.scrollLocker.getContainer()
- ) {
- this.scrollLocker.reLock({
- container: getParent(getContainer) as HTMLElement,
- });
- }
- };
-
- updateOpenCount = (prevProps?: Partial) => {
- const { visible: prevVisible, getContainer: prevGetContainer } =
- prevProps || {};
- const { visible, getContainer } = this.props;
-
- // Update count
- if (
- visible !== prevVisible &&
- supportDom &&
- getParent(getContainer) === document.body
- ) {
- if (visible && !prevVisible) {
- openCount += 1;
- } else if (prevProps) {
- openCount -= 1;
- }
- }
-
- // Clean up container if needed
- const getContainerIsFunc =
- typeof getContainer === 'function' &&
- typeof prevGetContainer === 'function';
- if (
- getContainerIsFunc
- ? getContainer.toString() !== prevGetContainer.toString()
- : getContainer !== prevGetContainer
- ) {
- this.removeCurrentContainer();
- }
- };
-
- componentWillUnmount() {
- const { visible, getContainer } = this.props;
- if (supportDom && getParent(getContainer) === document.body) {
- // 离开时不会 render, 导到离开时数值不变,改用 func 。。
- openCount = visible && openCount ? openCount - 1 : openCount;
- }
- this.removeCurrentContainer();
- raf.cancel(this.rafId);
- }
-
- attachToParent = (force = false) => {
- if (force || (this.container && !this.container.parentNode)) {
- const parent = getParent(this.props.getContainer);
- if (parent) {
- parent.appendChild(this.container);
- return true;
- }
-
- return false;
- }
-
- return true;
- };
-
- getContainer = () => {
- if (!supportDom) {
- return null;
- }
- if (!this.container) {
- this.container = document.createElement('div');
- this.attachToParent(true);
- }
- this.setWrapperClassName();
- return this.container;
- };
-
- setWrapperClassName = () => {
- const { wrapperClassName } = this.props;
- if (
- this.container &&
- wrapperClassName &&
- wrapperClassName !== this.container.className
- ) {
- this.container.className = wrapperClassName;
- }
- };
-
- removeCurrentContainer = () => {
- // Portal will remove from `parentNode`.
- // Let's handle this again to avoid refactor issue.
- this.container?.parentNode?.removeChild(this.container);
- };
-
- /**
- * Enhance ./switchScrollingEffect
- * 1. Simulate document body scroll bar with
- * 2. Record body has overflow style and recover when all of PortalWrapper invisible
- * 3. Disable body scroll when PortalWrapper has open
- *
- * @memberof PortalWrapper
- */
- switchScrollingEffect = () => {
- if (openCount === 1 && !Object.keys(cacheOverflow).length) {
- // Must be set after switchScrollingEffect
- cacheOverflow = setStyle({
- overflow: 'hidden',
- overflowX: 'hidden',
- overflowY: 'hidden',
- });
- } else if (!openCount) {
- setStyle(cacheOverflow);
- cacheOverflow = {};
- }
- };
-
- render() {
- const { children, forceRender, visible } = this.props;
- let portal = null;
- const childProps = {
- getOpenCount: () => openCount,
- getContainer: this.getContainer,
- switchScrollingEffect: this.switchScrollingEffect,
- scrollLocker: this.scrollLocker,
- };
-
- if (forceRender || visible || this.componentRef.current) {
- portal = (
-
- {children(childProps)}
-
- );
- }
- return portal;
- }
-}
-
-export default PortalWrapper;
diff --git a/src/index.ts b/src/index.ts
index 24c69d83..f99817ed 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -59,4 +59,4 @@ export { render, unmount } from './React/render';
export { spyElementPrototype, spyElementPrototypes } from './test/domHook';
export { default as Portal } from './Portal';
export type { PortalProps, PortalRef } from './Portal';
-export type { GetContainer } from './PortalWrapper';
+export type GetContainer = string | HTMLElement | (() => HTMLElement);
diff --git a/tests/Portal.test.tsx b/tests/Portal.test.tsx
index 6c84fecc..c137f12e 100644
--- a/tests/Portal.test.tsx
+++ b/tests/Portal.test.tsx
@@ -1,39 +1,8 @@
-/* eslint-disable react/no-array-index-key */
-import { act, render } from '@testing-library/react';
+import { render } from '@testing-library/react';
import React, { StrictMode, useEffect } from 'react';
import Portal from '../src/Portal';
-import PortalWrapper, { getOpenCount } from '../src/PortalWrapper';
describe('Portal', () => {
- let domContainer: HTMLDivElement;
-
- // Mock for raf
- window.requestAnimationFrame = callback => window.setTimeout(callback);
- window.cancelAnimationFrame = id => window.clearTimeout(id);
-
- beforeEach(() => {
- domContainer = document.createElement('div');
- document.body.appendChild(domContainer);
- });
-
- afterEach(() => {
- document.body.removeChild(domContainer);
- });
-
- it('forceRender', () => {
- const divRef = React.createRef();
-
- const { unmount } = render(
-
- {() => 2333
}
- ,
- );
-
- expect(divRef.current).toBeTruthy();
-
- unmount();
- });
-
it('didUpdate', () => {
const didUpdate = jest.fn();
@@ -60,136 +29,6 @@ describe('Portal', () => {
expect(didUpdate).toHaveBeenCalledTimes(2);
});
- describe('getContainer', () => {
- it('string', () => {
- const div = document.createElement('div');
- div.id = 'bamboo-light';
- document.body.appendChild(div);
-
- render(
-
- {() => 2333
}
- ,
- );
-
- expect(document.querySelector('#bamboo-light').childElementCount).toEqual(
- 1,
- );
-
- document.body.removeChild(div);
- });
-
- it('function', () => {
- const div = document.createElement('div');
-
- render(
- div}>
- {() => 2333
}
- ,
- );
-
- expect(div.childElementCount).toEqual(1);
- });
-
- it('htmlElement', () => {
- const div = document.createElement('div');
-
- render(
-
- {() => 2333
}
- ,
- );
-
- expect(div.childElementCount).toEqual(1);
- });
-
- it('delay', () => {
- jest.useFakeTimers();
- const divRef = React.createRef();
- render(
-
-
divRef.current}>
- {() => }
-
-
-
,
- );
-
- act(() => {
- jest.runAllTimers();
- });
-
- expect(divRef.current.childElementCount).toEqual(1);
- jest.useRealTimers();
- });
- });
-
- describe('openCount', () => {
- it('start as 0', () => {
- expect(getOpenCount()).toEqual(0);
-
- const { rerender, unmount } = render(
- {() => 2333
},
- );
- expect(getOpenCount()).toEqual(0);
-
- rerender({() => 2333
});
- expect(getOpenCount()).toEqual(1);
-
- unmount();
- });
-
- it('correct count', () => {
- const Demo = ({
- count,
- visible,
- }: {
- count: number;
- visible: boolean;
- }) => {
- return (
- <>
- {new Array(count).fill(null).map((_, index) => (
-
- {() => 2333
}
-
- ))}
- >
- );
- };
-
- expect(getOpenCount()).toEqual(0);
-
- const { rerender } = render();
- expect(getOpenCount()).toEqual(1);
-
- rerender();
- expect(getOpenCount()).toEqual(2);
-
- rerender();
- expect(getOpenCount()).toEqual(1);
-
- rerender();
- expect(getOpenCount()).toEqual(0);
- });
- });
-
- it('wrapperClassName', () => {
- const { rerender } = render(
-
- {() => }
- ,
- );
- expect(document.body.querySelector('.bamboo')).toBeTruthy();
-
- rerender(
-
- {() => }
- ,
- );
- expect(document.body.querySelector('.light')).toBeTruthy();
- });
-
it('should restore to original place in StrictMode', () => {
const parentContainer = document.createElement('div');
const curDomContainer = document.createElement('div');