diff --git a/docs/demo/fragment.md b/docs/demo/fragment.md
deleted file mode 100644
index de859a4..0000000
--- a/docs/demo/fragment.md
+++ /dev/null
@@ -1,8 +0,0 @@
----
-title: fragment
-nav:
- title: Demo
- path: /demo
----
-
-
diff --git a/docs/examples/custom-icon.tsx b/docs/examples/custom-icon.tsx
index ea3df8e..96b24f7 100644
--- a/docs/examples/custom-icon.tsx
+++ b/docs/examples/custom-icon.tsx
@@ -1,6 +1,7 @@
-import Collapse, { Panel } from 'rc-collapse';
+import Collapse from 'rc-collapse';
import * as React from 'react';
import '../../assets/index.less';
+import type { ItemType } from '../../src/interface';
import motion from './_util/motionUtil';
const initLength = 3;
@@ -48,31 +49,54 @@ const App: React.FC = () => {
const time = random();
- const panelItems = Array.from
,
+ },
+ ]}
+ />
+ ),
+ },
+ {
+ key: initLength + 2,
+ header: `This is panel header ${initLength + 2}`,
+ children: (
+
+
+
+
+ ),
+ },
+ ]}
+ />
+ ),
+ },
);
const tools = (
@@ -104,9 +128,8 @@ const App: React.FC = () => {
activeKey={activeKey}
expandIcon={expandIcon}
openMotion={motion}
- >
- {panelItems}
-
+ items={panelItems}
+ />
>
);
};
diff --git a/docs/examples/fragment.tsx b/docs/examples/fragment.tsx
deleted file mode 100644
index bb38c5b..0000000
--- a/docs/examples/fragment.tsx
+++ /dev/null
@@ -1,23 +0,0 @@
-import Collapse, { Panel } from 'rc-collapse';
-import * as React from 'react';
-import { Fragment } from 'react';
-import '../../assets/index.less';
-
-const App = () => (
-
- content
- content
-
- content
- content
-
-
-
- content
- content
-
-
-
-);
-
-export default App;
diff --git a/docs/examples/simple.tsx b/docs/examples/simple.tsx
index 5353415..2201d43 100644
--- a/docs/examples/simple.tsx
+++ b/docs/examples/simple.tsx
@@ -1,7 +1,8 @@
import type { CollapseProps } from 'rc-collapse';
-import Collapse, { Panel } from 'rc-collapse';
+import Collapse from 'rc-collapse';
import * as React from 'react';
import '../../assets/index.less';
+import type { ItemType } from '../../src/interface';
import motion from './_util/motionUtil';
const initLength = 3;
@@ -50,38 +51,60 @@ const App: React.FC = () => {
const time = random();
- const panelItems = Array.from({ length: initLength }, (_, i) => {
+ const panelItems = Array.from({ length: initLength }, (_, i) => {
const key = i + 1;
- return (
-
- {text.repeat(time)}
-
- );
+ return {
+ key,
+ header: `This is panel header ${key}`,
+ children: {text.repeat(time)}
,
+ };
}).concat(
-
-
-
-
- ,
-
-
-
-
-
-
- ,
- Extra Node}
- >
- Panel with extra
- ,
+ {
+ key: initLength + 1,
+ header: `This is panel header ${initLength + 1}`,
+ children: (
+ {text},
+ },
+ ]}
+ />
+ ),
+ },
+ {
+ key: initLength + 2,
+ header: `This is panel header ${initLength + 2}`,
+ children: (
+
+
+
+
+ ),
+ },
+ ]}
+ />
+ ),
+ },
+ {
+ key: initLength + 3,
+ header: `This is panel header ${initLength + 3}`,
+ extra: Extra Node,
+ children: Panel with extra
,
+ },
);
const handleCollapsibleChange = (e: React.ChangeEvent) => {
@@ -129,9 +152,8 @@ const App: React.FC = () => {
expandIcon={expandIcon}
openMotion={motion}
collapsible={collapsible}
- >
- {panelItems}
-
+ items={panelItems}
+ />
>
);
};
diff --git a/src/Collapse.tsx b/src/Collapse.tsx
index 36267d2..52519ef 100644
--- a/src/Collapse.tsx
+++ b/src/Collapse.tsx
@@ -1,6 +1,5 @@
import classNames from 'classnames';
import useMergedState from 'rc-util/lib/hooks/useMergedState';
-import warning from 'rc-util/lib/warning';
import React from 'react';
import useItems from './hooks/useItems';
import type { CollapseProps } from './interface';
@@ -23,7 +22,6 @@ const Collapse = React.forwardRef((props, ref) =>
style,
accordion,
className,
- children,
collapsible,
openMotion,
expandIcon,
@@ -58,12 +56,7 @@ const Collapse = React.forwardRef((props, ref) =>
});
// ======================== Children ========================
- warning(
- !children,
- '`children` will be removed in next major version. Please use `items` instead.',
- );
-
- const mergedChildren = useItems(items, children, {
+ const mergedChildren = useItems(items, {
prefixCls,
accordion,
openMotion,
diff --git a/src/hooks/useItems.tsx b/src/hooks/useItems.tsx
index 2bc5db7..cc39737 100644
--- a/src/hooks/useItems.tsx
+++ b/src/hooks/useItems.tsx
@@ -1,4 +1,3 @@
-import toArray from 'rc-util/lib/Children/toArray';
import React from 'react';
import type { CollapsePanelProps, CollapseProps, ItemType } from '../interface';
import CollapsePanel from '../Panel';
@@ -31,8 +30,6 @@ const convertItemsToNodes = (items: ItemType[], props: Props) => {
...restProps
} = item;
- // You may be puzzled why you want to convert them all into strings, me too.
- // Maybe: https://github.com/react-component/collapse/blob/aac303a8b6ff30e35060b4f8fecde6f4556fcbe2/src/Collapse.tsx#L15
const key = String(rawKey ?? index);
const mergeCollapsible = rawCollapsible ?? collapsible;
const mergeDestroyInactivePanel = rawDestroyInactivePanel ?? destroyInactivePanel;
@@ -71,92 +68,12 @@ const convertItemsToNodes = (items: ItemType[], props: Props) => {
});
};
-/**
- * @deprecated The next major version will be removed
- */
-const getNewChild = (
- child: React.ReactElement,
- index: number,
- props: Props,
-) => {
- if (!child) return null;
-
- const {
- prefixCls,
- accordion,
- collapsible,
- destroyInactivePanel,
- onItemClick,
- activeKey,
- openMotion,
- expandIcon,
- } = props;
-
- const key = child.key || String(index);
-
- const {
- header,
- headerClass,
- destroyInactivePanel: childDestroyInactivePanel,
- collapsible: childCollapsible,
- onItemClick: childOnItemClick,
- } = child.props;
-
- let isActive = false;
- if (accordion) {
- isActive = activeKey[0] === key;
- } else {
- isActive = activeKey.indexOf(key) > -1;
- }
-
- const mergeCollapsible = childCollapsible ?? collapsible;
-
- const handleItemClick = (value: React.Key) => {
- if (mergeCollapsible === 'disabled') return;
- onItemClick(value);
- childOnItemClick?.(value);
- };
-
- const childProps = {
- key,
- panelKey: key,
- header,
- headerClass,
- isActive,
- prefixCls,
- destroyInactivePanel: childDestroyInactivePanel ?? destroyInactivePanel,
- openMotion,
- accordion,
- children: child.props.children,
- onItemClick: handleItemClick,
- expandIcon,
- collapsible: mergeCollapsible,
- };
-
- // https://github.com/ant-design/ant-design/issues/20479
- if (typeof child.type === 'string') {
- return child;
- }
-
- Object.keys(childProps).forEach((propName) => {
- if (typeof childProps[propName] === 'undefined') {
- delete childProps[propName];
- }
- });
-
- return React.cloneElement(child, childProps);
-};
-
-function useItems(
- items?: ItemType[],
- rawChildren?: React.ReactNode,
- props?: Props,
-): React.ReactElement[] {
+function useItems(items?: ItemType[], props?: Props) {
if (Array.isArray(items)) {
return convertItemsToNodes(items, props);
}
- return toArray(rawChildren).map((child, index) => getNewChild(child, index, props));
+ return null;
}
export default useItems;
diff --git a/src/index.tsx b/src/index.tsx
index 8e963c6..87e21e7 100644
--- a/src/index.tsx
+++ b/src/index.tsx
@@ -1,10 +1,2 @@
-import Collapse from './Collapse';
-
+export { default } from './Collapse';
export type { CollapsePanelProps, CollapseProps } from './interface';
-
-export default Collapse;
-
-/**
- * @deprecated use `items` instead, will be removed in `v4.0.0`
- */
-export const { Panel } = Collapse;
diff --git a/tests/index.spec.tsx b/tests/index.spec.tsx
index 533df08..cd2a509 100644
--- a/tests/index.spec.tsx
+++ b/tests/index.spec.tsx
@@ -1,8 +1,8 @@
import type { RenderResult } from '@testing-library/react';
import { fireEvent, render } from '@testing-library/react';
import KeyCode from 'rc-util/lib/KeyCode';
-import React, { Fragment } from 'react';
-import Collapse, { Panel } from '../src/index';
+import React from 'react';
+import Collapse from '../src/index';
import type { CollapseProps, ItemType } from '../src/interface';
describe('collapse', () => {
@@ -24,6 +24,27 @@ describe('collapse', () => {
}
}
+ const items: ItemType[] = [
+ {
+ key: '1',
+ label: 'collapse 1',
+ collapsible: 'disabled',
+ children: 'first',
+ },
+ {
+ key: '2',
+ label: 'collapse 2',
+ extra: ExtraSpan,
+ children: 'second',
+ },
+ {
+ key: '3',
+ label: 'collapse 3',
+ className: 'important',
+ children: 'third',
+ },
+ ];
+
function runNormalTest(element: any) {
let collapse: RenderResult;
@@ -115,21 +136,7 @@ describe('collapse', () => {
describe('collapse', () => {
const expandIcon = () => test{'>'};
- const element = (
-
-
- first
-
- ExtraSpan}>
- second
-
-
- third
-
-
- );
-
- runNormalTest(element);
+ runNormalTest();
it('controlled', () => {
const onChangeSpy = jest.fn();
@@ -143,17 +150,27 @@ describe('collapse', () => {
};
return (
-
-
- first
-
-
- second
-
-
- third
-
-
+
);
};
@@ -170,31 +187,32 @@ describe('collapse', () => {
});
describe('it should support number key', () => {
- const expandIcon = () => test{'>'};
- const element = (
-
-
- first
-
- ExtraSpan}>
- second
-
-
- third
-
-
+ runNormalTest(
+ test{'>'}}
+ items={items.map((item) => ({
+ ...item,
+ key: Number(item.key),
+ }))}
+ />,
);
-
- runNormalTest(element);
});
it('shoule support extra whit number 0', () => {
const { container } = render(
-
-
- zero
-
- ,
+ ,
);
const extraNodes = container.querySelectorAll('.rc-collapse-extra');
@@ -204,17 +222,14 @@ describe('collapse', () => {
it('should support activeKey number 0', () => {
const { container } = render(
-
-
- zero
-
-
- first
-
-
- second
-
- ,
+ ({
+ ...item,
+ key: index,
+ }))}
+ />,
);
// activeKey number 0, should open one item
@@ -223,17 +238,7 @@ describe('collapse', () => {
it('click should toggle panel state', () => {
const { container } = render(
-
-
- first
-
-
- second
-
-
- third
-
- ,
+ ,
);
const header = container.querySelectorAll('.rc-collapse-header')?.[1];
@@ -313,59 +318,89 @@ describe('collapse', () => {
describe('prop: accordion', () => {
runAccordionTest(
-
-
- first
-
-
- second
-
-
- third
-
- ,
+ ,
);
});
describe('forceRender', () => {
it('when forceRender is not supplied it should lazy render the panel content', () => {
const { container } = render(
-
-
- first
-
-
- second
-
- ,
+ ,
);
expect(container.querySelectorAll('.rc-collapse-content')).toHaveLength(0);
});
it('when forceRender is FALSE it should lazy render the panel content', () => {
const { container } = render(
-
-
- first
-
-
- second
-
- ,
+ ,
);
expect(container.querySelectorAll('.rc-collapse-content')).toHaveLength(0);
});
it('when forceRender is TRUE then it should render all the panel content to the DOM', () => {
const { container } = render(
-
-
- first
-
-
- second
-
- ,
+ ,
);
jest.runAllTimers();
@@ -388,17 +423,26 @@ describe('collapse', () => {
};
const { container } = render(
-
-
- first
-
-
- second
-
-
- second
-
- ,
+ ,
);
fireEvent.keyPress(container.querySelectorAll('.rc-collapse-header')?.[2], myKeyEvent);
@@ -423,46 +467,59 @@ describe('collapse', () => {
);
});
- describe('wrapped in Fragment', () => {
- const expandIcon = () => test{'>'};
- const element = (
-
-
-
- first
-
- ExtraSpan}>
- second
-
-
-
- third
-
-
-
-
- );
-
- runNormalTest(element);
- });
+ // TODO: 移除 Panel 后需要在 Ant Design 里面测试,待 Ant Design 稳定后再移除 assignee: @wxh16144
+ // describe('wrapped in Fragment', () => {
+ // const expandIcon = () => test{'>'};
+ // const element = (
+ //
+ //
+ //
+ // first
+ //
+ // ExtraSpan}>
+ // second
+ //
+ //
+ //
+ // third
+ //
+ //
+ //
+ //
+ // );
+
+ // runNormalTest(element);
+ // });
it('should support return null icon', () => {
const { container } = render(
- null}>
-
- first
-
- ,
+ null}
+ items={[
+ {
+ key: '1',
+ label: 'title',
+ children: 'first',
+ },
+ ]}
+ />,
);
expect(container.querySelector('.rc-collapse-header')?.childNodes).toHaveLength(1);
});
- it('should support custom child', () => {
+ // TODO: 需要在 Ant Design 里面测试,待 Ant Design 稳定后再移除 assignee: @wxh16144
+ // 按理说我们不允许用户这样用,但是为了兼容性,我们还是保留这个测试
+ it.skip('should support custom child', () => {
const { container } = render(
-
-
- first
-
+
custom-child
,
);
@@ -472,44 +529,49 @@ describe('collapse', () => {
// https://github.com/ant-design/ant-design/issues/36327
// https://github.com/ant-design/ant-design/issues/6179
// https://github.com/react-component/collapse/issues/73#issuecomment-323626120
- it('should support custom component', () => {
- const PanelElement = (props) => (
-
- test
-
- );
- const { container } = render(
-
-
-
- second
-
- ,
- );
-
- expect(container.querySelectorAll('.rc-collapse-content-active')).toHaveLength(1);
- expect(container.querySelector('.rc-collapse-content')).toHaveClass(
- 'rc-collapse-content-active',
- );
- expect(container.querySelector('.rc-collapse-header')?.textContent).toBe('collapse 1');
- expect(container.querySelector('.rc-collapse-header')?.querySelectorAll('.arrow')).toHaveLength(
- 1,
- );
- fireEvent.click(container.querySelector('.rc-collapse-header')!);
- expect(container.querySelectorAll('.rc-collapse-content-active')).toHaveLength(0);
- expect(container.querySelector('.rc-collapse-content')).toHaveClass(
- 'rc-collapse-content-inactive',
- );
- });
+ // TODO: 需要在 Ant Design 里面测试,待 Ant Design 稳定后再移除 assignee: @wxh16144
+ // it('should support custom component', () => {
+ // const PanelElement = (props) => (
+ //
+ // test
+ //
+ // );
+ // const { container } = render(
+ //
+ //
+ //
+ // second
+ //
+ // ,
+ // );
+
+ // expect(container.querySelectorAll('.rc-collapse-content-active')).toHaveLength(1);
+ // expect(container.querySelector('.rc-collapse-content')).toHaveClass(
+ // 'rc-collapse-content-active',
+ // );
+ // expect(container.querySelector('.rc-collapse-header')?.textContent).toBe('collapse 1');
+ // expect(container.querySelector('.rc-collapse-header')?.querySelectorAll('.arrow')).toHaveLength(
+ // 1,
+ // );
+ // fireEvent.click(container.querySelector('.rc-collapse-header')!);
+ // expect(container.querySelectorAll('.rc-collapse-content-active')).toHaveLength(0);
+ // expect(container.querySelector('.rc-collapse-content')).toHaveClass(
+ // 'rc-collapse-content-inactive',
+ // );
+ // });
describe('prop: collapsible', () => {
it('default', () => {
const { container } = render(
-
-
- first
-
- ,
+ ,
);
expect(container.querySelector('.rc-collapse-header-text')).toBeTruthy();
fireEvent.click(container.querySelector('.rc-collapse-header')!);
@@ -517,11 +579,16 @@ describe('collapse', () => {
});
it('should work when value is header', () => {
const { container } = render(
-
-
- first
-
- ,
+ ,
);
expect(container.querySelector('.rc-collapse-header-text')).toBeTruthy();
fireEvent.click(container.querySelector('.rc-collapse-header')!);
@@ -531,11 +598,16 @@ describe('collapse', () => {
});
it('should work when value is icon', () => {
const { container } = render(
-
-
- first
-
- ,
+ ,
);
expect(container.querySelector('.rc-collapse-expand-icon')).toBeTruthy();
fireEvent.click(container.querySelector('.rc-collapse-header')!);
@@ -546,11 +618,16 @@ describe('collapse', () => {
it('should disabled when value is disabled', () => {
const { container } = render(
-
-
- first
-
- ,
+ ,
);
expect(container.querySelector('.rc-collapse-header-text')).toBeTruthy();
expect(container.querySelectorAll('.rc-collapse-item-disabled')).toHaveLength(1);
@@ -560,11 +637,17 @@ describe('collapse', () => {
it('the value of panel should be read first', () => {
const { container } = render(
-
-
- first
-
- ,
+ ,
);
expect(container.querySelector('.rc-collapse-header-text')).toBeTruthy();
@@ -576,11 +659,16 @@ describe('collapse', () => {
it('icon trigger when collapsible equal header', () => {
const { container } = render(
-
-
- first
-
- ,
+ ,
);
fireEvent.click(container.querySelector('.rc-collapse-header .arrow')!);
@@ -589,11 +677,16 @@ describe('collapse', () => {
it('header not trigger when collapsible equal icon', () => {
const { container } = render(
-
-
- first
-
- ,
+ ,
);
fireEvent.click(container.querySelector('.rc-collapse-header-text')!);
@@ -603,11 +696,16 @@ describe('collapse', () => {
it('!showArrow', () => {
const { container } = render(
-
-
- first
-
- ,
+ ,
);
expect(container.querySelectorAll('.rc-collapse-expand-icon')).toHaveLength(0);
@@ -616,46 +714,38 @@ describe('collapse', () => {
it('Panel container dom can set event handler', () => {
const clickHandler = jest.fn();
const { container } = render(
-
-
- Click this
-
- ,
+ Click this,
+ },
+ ]}
+ />,
);
fireEvent.click(container.querySelector('.target')!);
expect(clickHandler).toHaveBeenCalled();
});
- it('falsy Panel', () => {
- const { container } = render(
-
- {null}
-
- Panel 1 content
-
- {0}
-
- Panel 2 content
-
- {undefined}
- {false}
- {true}
- ,
- );
-
- expect(container.querySelectorAll('.rc-collapse-item')).toHaveLength(2);
- });
-
it('ref should work', () => {
const ref = React.createRef();
const panelRef = React.createRef();
const { container } = render(
-
-
- first
-
- ,
+ ,
);
expect(ref.current).toBe(container.firstChild);
expect(panelRef.current).toBe(container.querySelector('.rc-collapse-item'));
@@ -665,11 +755,16 @@ describe('collapse', () => {
it('onItemClick should work', () => {
const onItemClick = jest.fn();
const { container } = render(
-
-
- first
-
- ,
+ ,
);
fireEvent.click(container.querySelector('.rc-collapse-header')!);
expect(onItemClick).toHaveBeenCalled();
@@ -678,11 +773,17 @@ describe('collapse', () => {
it('onItemClick should not work when collapsible is disabled', () => {
const onItemClick = jest.fn();
const { container } = render(
-
-
- first
-
- ,
+ ,
);
fireEvent.click(container.querySelector('.rc-collapse-header')!);
expect(onItemClick).not.toHaveBeenCalled();
@@ -690,65 +791,24 @@ describe('collapse', () => {
it('panel style should work', () => {
const { container } = render(
-
-
- first
-
- ,
- );
- expect(container.querySelector('.rc-collapse-item').style.color).toBe('red');
- });
-
- describe('props items', () => {
- const items: ItemType[] = [
- {
- key: '1',
- label: 'collapse 1',
- children: 'first',
- collapsible: 'disabled',
- },
- {
- key: '2',
- label: 'collapse 2',
- children: 'second',
- extra: ExtraSpan,
- },
- {
- key: '3',
- label: 'collapse 3',
- className: 'important',
- children: 'third',
- },
- ];
-
- runNormalTest(
- test{'>'}} items={items} />,
- );
-
- runAccordionTest(
,
);
+ expect(window.getComputedStyle(container.querySelector('.rc-collapse-item'))).toHaveProperty(
+ 'color',
+ 'red',
+ );
+ });
+ describe('props items', () => {
it('should work with onItemClick', () => {
const onItemClick = jest.fn();
const { container } = render(