From bd2361490eea49a1957c3215510c731224a941c9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E5=B0=8F=E8=B1=AA?= <1844749591@qq.com>
Date: Sat, 4 Jan 2025 22:38:20 +0800
Subject: [PATCH 1/4] feat: retire deprecated api
---
.gitignore | 3 +-
src/Collapse.tsx | 16 +-
src/hooks/useItems.tsx | 89 +-----
src/index.tsx | 5 -
tests/index.spec.tsx | 648 ++++++++++++++++++++++++++---------------
5 files changed, 414 insertions(+), 347 deletions(-)
diff --git a/.gitignore b/.gitignore
index 2623981..c1840f9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -38,4 +38,5 @@ package-lock.json
.env.local
src/.umi
-bun.lockb
\ No newline at end of file
+bun.lockb
+.vscode/
\ No newline at end of file
diff --git a/src/Collapse.tsx b/src/Collapse.tsx
index 0623138..333e593 100644
--- a/src/Collapse.tsx
+++ b/src/Collapse.tsx
@@ -1,10 +1,8 @@
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';
-import CollapsePanel from './Panel';
import pickAttrs from 'rc-util/lib/pickAttrs';
function getActiveKeysArray(activeKey: React.Key | React.Key[]) {
@@ -59,12 +57,7 @@ const Collapse = React.forwardRef((props, ref) =>
});
// ======================== Children ========================
- warning(
- !children,
- '[rc-collapse] `children` will be removed in next major version. Please use `items` instead.',
- );
-
- const mergedChildren = useItems(items, children, {
+ const mergedChildren = useItems(items, {
prefixCls,
accordion,
openMotion,
@@ -89,9 +82,4 @@ const Collapse = React.forwardRef((props, ref) =>
);
});
-export default Object.assign(Collapse, {
- /**
- * @deprecated use `items` instead, will be removed in `v4.0.0`
- */
- Panel: CollapsePanel,
-});
+export default Collapse;
diff --git a/src/hooks/useItems.tsx b/src/hooks/useItems.tsx
index 2bc5db7..4108fa7 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';
@@ -71,92 +70,8 @@ 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[] {
- if (Array.isArray(items)) {
- return convertItemsToNodes(items, props);
- }
-
- return toArray(rawChildren).map((child, index) => getNewChild(child, index, props));
+function useItems(items?: ItemType[], props?: Props): React.ReactElement[] {
+ return convertItemsToNodes(items, props);
}
export default useItems;
diff --git a/src/index.tsx b/src/index.tsx
index 8e963c6..428b33f 100644
--- a/src/index.tsx
+++ b/src/index.tsx
@@ -3,8 +3,3 @@ import Collapse 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 c08d7ce..dd9f3c5 100644
--- a/tests/index.spec.tsx
+++ b/tests/index.spec.tsx
@@ -2,7 +2,7 @@ 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 Collapse from '../src/index';
import type { CollapseProps, ItemType } from '../src/interface';
describe('collapse', () => {
@@ -116,17 +116,30 @@ describe('collapse', () => {
const expandIcon = () => test{'>'};
const element = (
-
-
- first
-
- ExtraSpan}>
- second
-
-
- third
-
-
+ ExtraSpan,
+ children: 'second',
+ },
+ {
+ key: '3',
+ label: 'collapse 3',
+ className: 'important',
+ children: 'third',
+ },
+ ]}
+ />
);
runNormalTest(element);
@@ -143,17 +156,27 @@ describe('collapse', () => {
};
return (
-
-
- first
-
-
- second
-
-
- third
-
-
+
);
};
@@ -172,17 +195,30 @@ describe('collapse', () => {
describe('it should support number key', () => {
const expandIcon = () => test{'>'};
const element = (
-
-
- first
-
- ExtraSpan}>
- second
-
-
- third
-
-
+ ExtraSpan,
+ children: 'second',
+ },
+ {
+ key: 3,
+ label: 'collapse 3',
+ className: 'important',
+ children: 'third',
+ },
+ ]}
+ />
);
runNormalTest(element);
@@ -191,11 +227,17 @@ describe('collapse', () => {
describe('prop: headerClass', () => {
it('applies the passed headerClass to the header', () => {
const element = (
-
-
- first
-
-
+
);
const { container } = render(element);
@@ -207,11 +249,18 @@ describe('collapse', () => {
it('should support extra whit number 0', () => {
const { container } = render(
-
-
- zero
-
- ,
+ ,
);
const extraNodes = container.querySelectorAll('.rc-collapse-extra');
@@ -221,17 +270,27 @@ describe('collapse', () => {
it('should support activeKey number 0', () => {
const { container } = render(
-
-
- zero
-
-
- first
-
-
- second
-
- ,
+ ,
);
// activeKey number 0, should open one item
@@ -240,17 +299,28 @@ describe('collapse', () => {
it('click should toggle panel state', () => {
const { container } = render(
-
-
- first
-
-
- second
-
-
- third
-
- ,
+ ,
);
const header = container.querySelectorAll('.rc-collapse-header')?.[1];
@@ -330,59 +400,92 @@ 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();
@@ -405,17 +508,26 @@ describe('collapse', () => {
};
const { container } = render(
-
-
- first
-
-
- second
-
-
- third
-
- ,
+ ,
);
fireEvent.keyDown(container.querySelectorAll('.rc-collapse-header')?.[2], myKeyEvent);
@@ -443,21 +555,30 @@ describe('collapse', () => {
describe('wrapped in Fragment', () => {
const expandIcon = () => test{'>'};
const element = (
-
-
-
- first
-
- ExtraSpan}>
- second
-
-
-
- third
-
-
-
-
+ ExtraSpan,
+ children: 'second',
+ },
+ {
+ key: '3',
+ label: 'collapse 3',
+ className: 'important',
+ children: 'third',
+ },
+ ]}
+ />
);
runNormalTest(element);
@@ -465,43 +586,40 @@ describe('collapse', () => {
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', () => {
- const { container } = render(
-
-
- first
-
- custom-child
- ,
- );
- expect(container.querySelector('.custom-child')?.innerHTML).toBe('custom-child');
- });
-
// 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
-
- ,
+ test
,
+ },
+ {
+ key: '2',
+ label: 'collapse 2',
+ children: 'second',
+ },
+ ]}
+ />,
);
expect(container.querySelectorAll('.rc-collapse-content-active')).toHaveLength(1);
@@ -522,23 +640,33 @@ describe('collapse', () => {
describe('prop: collapsible', () => {
it('default', () => {
const { container } = render(
-
-
- first
-
- ,
+ ,
);
expect(container.querySelector('.rc-collapse-header-text')).toBeTruthy();
fireEvent.click(container.querySelector('.rc-collapse-header')!);
expect(container.querySelectorAll('.rc-collapse-item-active')).toHaveLength(1);
});
+
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')!);
@@ -546,13 +674,19 @@ describe('collapse', () => {
fireEvent.click(container.querySelector('.rc-collapse-header-text')!);
expect(container.querySelectorAll('.rc-collapse-item-active')).toHaveLength(1);
});
+
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')!);
@@ -563,11 +697,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);
@@ -577,11 +716,17 @@ describe('collapse', () => {
it('the value of panel should be read first', () => {
const { container } = render(
-
-
- first
-
- ,
+ ,
);
expect(container.querySelector('.rc-collapse-header-text')).toBeTruthy();
@@ -593,11 +738,16 @@ describe('collapse', () => {
it('icon trigger when collapsible equal header', () => {
const { container } = render(
-
-
- first
-
- ,
+ ,
);
fireEvent.click(container.querySelector('.rc-collapse-header .arrow')!);
@@ -606,11 +756,16 @@ describe('collapse', () => {
it('header not trigger when collapsible equal icon', () => {
const { container } = render(
-
-
- first
-
- ,
+ ,
);
fireEvent.click(container.querySelector('.rc-collapse-header-text')!);
@@ -620,11 +775,16 @@ describe('collapse', () => {
it('!showArrow', () => {
const { container } = render(
-
-
- first
-
- ,
+ ,
);
expect(container.querySelectorAll('.rc-collapse-expand-icon')).toHaveLength(0);
@@ -633,46 +793,38 @@ describe('collapse', () => {
it('Panel container dom can set event handler', () => {
const clickHandler = jest.fn();
const { container } = render(
-
-
- Click this
-
- ,
+ Click this,
+ onClick: clickHandler,
+ },
+ ]}
+ />,
);
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'));
@@ -682,11 +834,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();
@@ -695,11 +852,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();
@@ -707,11 +870,16 @@ describe('collapse', () => {
it('panel style should work', () => {
const { container } = render(
-
-
- first
-
- ,
+ ,
);
expect(container.querySelector('.rc-collapse-item')).toHaveStyle({ color: 'red' });
});
From 2e300a53b6cc54436acdd7807355e25c37cadc87 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E5=B0=8F=E8=B1=AA?= <1844749591@qq.com>
Date: Sat, 4 Jan 2025 22:46:33 +0800
Subject: [PATCH 2/4] fix: lint fix
---
src/Collapse.tsx | 1 -
1 file changed, 1 deletion(-)
diff --git a/src/Collapse.tsx b/src/Collapse.tsx
index 333e593..6d2e2f3 100644
--- a/src/Collapse.tsx
+++ b/src/Collapse.tsx
@@ -22,7 +22,6 @@ const Collapse = React.forwardRef((props, ref) =>
style,
accordion,
className,
- children,
collapsible,
openMotion,
expandIcon,
From 3fa129b22f088c91a18a9a146d0c298907b65085 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E5=B0=8F=E8=B1=AA?= <1844749591@qq.com>
Date: Sat, 4 Jan 2025 22:55:44 +0800
Subject: [PATCH 3/4] chore: update demo
---
docs/examples/custom-icon.tsx | 83 +++++++++++++++++++-----------
docs/examples/fragment.tsx | 23 ---------
docs/examples/simple.tsx | 96 +++++++++++++++++++++--------------
3 files changed, 112 insertions(+), 90 deletions(-)
delete mode 100644 docs/examples/fragment.tsx
diff --git a/docs/examples/custom-icon.tsx b/docs/examples/custom-icon.tsx
index ea3df8e..9cbb557 100644
--- a/docs/examples/custom-icon.tsx
+++ b/docs/examples/custom-icon.tsx
@@ -1,4 +1,4 @@
-import Collapse, { Panel } from 'rc-collapse';
+import Collapse from 'rc-collapse';
import * as React from 'react';
import '../../assets/index.less';
import motion from './_util/motionUtil';
@@ -48,32 +48,56 @@ const App: React.FC = () => {
const time = random();
- const panelItems = Array.from